資料庫的使用你可能忽略了這些

it米粉發表於2019-02-26

資料庫的管理是一個非常專業的事情,對資料庫的調優、監控一般是由資料庫工程師完成,但是開發人員也經常與資料庫打交道,即使是簡單的增刪改查也是有很多竅門,這裡,一起來聊聊資料庫中很容易忽略的問題。

欄位長度省著點用

先說說我們常用的型別的儲存長度:

列型別 儲存長度
tinyint 1位元組
smallint 2位元組
int 4位元組
bigint 8位元組
float 4位元組
decimal(m,d) 0-4位元組
datetime 8位元組
timestamp 4位元組
char(m) m個位元組
varchar(m) 可變長度
text 可變長度

很明顯,不同的型別儲存的長度有很大區別的,對查詢的效率有影響,欄位長度對索引的影響是很大的。

  • 字串欄位長度都差不多的,可以預估長度的,用char
  • 字串長度差異大,用varchar,限制長度,不要浪費空間
  • 整型根據大小,選擇合適的型別
  • 時間建議用timestamp
  • 建議使用decimal,不建議使用float,如果是價格,可以考慮用int或bigint,如1元,儲存的就是100

放棄uuid(guid)的使用

不管是uuid,還是guid,使用的時候都是為了避免同時生成重複的ID,但是建議考慮其他方案,原因如下:

  • uuid沒有順序
  • uuid太長
  • uuid規則完全不可控

推薦的方案用bigint(首選),或者char來儲存,生成方式參考snowflake的演算法,有順序、長度固定、比uuid更短,當然,也幾乎不會重複。

大表減少聯表,最好是單表查詢

單表查詢的優勢很多,查詢效率極高,便於分表分庫擴充套件,但是很多時候大家都覺得真正實現起來不太現實,完全失去了關聯式資料庫的意義,但是單表的效能優勢太明顯,一般總會有辦法解決的:

  • 合理的冗餘欄位
  • 配合記憶體資料庫(redis\mongodb)使用
  • 聯表變多次查詢(下文會有說明)

如果考慮都後期資料量大,需要分表分庫,就應該儘早實時單表查詢,現在的資料庫分表分庫的中介軟體基本都無法支援聯表查詢。即使如mycat最多支援兩個表的聯表查詢,但是也有很明顯的效能損耗。

索引的正確處理方式

索引的優勢這裡就不多說了,索引使用不當會有反效果:

  • 資料量很小的表,不需要索引
  • 一個表的索引不宜過多,建議最多就5個,索引不可能滿足所有的場景,但是了個滿足絕大部分的場景
  • mysql 和 sqlserver的索引差別還挺大的,需要注意。例如:
    mysql索引欄位的順序對效能有很大影響,sqlserver優化過,影響很小

多查幾次比聯表可能要好

提出這個方案相信會得到很多人的反對,但是我相信這個結論還是非常適合資料量大的場景。多查幾次資料庫有這麼幾個弊端:

  • 增加了網路消耗
  • 增加了資料庫的連線數

其實,這兩個問題在現在基本都可以忽略的,資料庫和應用的連線基本都是內網,這個網路連線的效率還是很高的。資料庫對連線池的優化已經比較成熟了,連線數只要不是太多,影響也不會太嚴重,但是多查幾次的優勢卻很多:

  • 單表效率更高
  • 便於後期擴充套件分表分庫庫
  • 有效利用資料庫本身的結果快取
  • 減少鎖表,聯表會鎖多個表

當然,多查幾次這個度一定要把握。千萬不要在一個迴圈裡面查詢資料庫。我們也應該儘量減少查詢資料庫的次數。我們可以接受1次查詢變2次查詢,如果你變成10次查詢,那就要放棄了。
舉個例子:
查詢商品的時候,需要顯示分類表的分類名

select category.name,product.name from product  inner join category on p.categoryid=category.id複製程式碼

建議的方式:

select categoryid,name  from product 
select categoryname from category where categoryid in ('','','','')複製程式碼

當然,你可以再優化一下,查詢分類名之前,對product的categoryid排序一下,這樣速度更快。因為我們前面已經用snowflake生成了有順序的主鍵了。
補充一下,in的效率並不是你想象的那麼慢,如果保持在100個節點(很多書籍介紹1000個節點,我們保守一點),效能還是很高的。

儘量使用簡單的資料庫指令碼

很多用過 .net Entity Framework 的人都說這個框架太慢,其實慢主要是兩點:錯誤的使用延遲載入(外來鍵關聯)、生成SQL編譯太慢。Entity Framework生成的SQL指令碼有太多沒用的東西,導致編譯太慢。
資料庫指令碼儘量使用簡單的,不要用太長的一個SQL指令碼,會導致初次執行的時候,編譯SQL指令碼花費太多的時間。

儘量去避免聚合操作

聚合操作如count,group等,是資料庫效能的大殺手,經常會出現大面積的表掃描和索表的情況,所以大家能看到很多平臺都把數量的計算給隱藏了,商品查詢不去實時顯示count的結果。如淘寶,就不顯示查詢結果的數量,只是顯示前100頁。
避免聚合操作的方法就是將實時的count計算結果用欄位去儲存,去累加這個結果。當然,也可以考慮用spark等實時計算框架去處理,這種高深的技術,不在此次討論範圍內。(PS:主要是我也不懂)

總結

程式的優化很多時候都是一些細節的問題,更應該注意平時的積累,阿里SQL的規範有很多可以吸取的地方,以上也是自己工作中的一些總結。
(完)


歡迎大家關注我的公眾號交流、學習、第一時間獲取最新的文章。
微訊號:itmifen

相關文章