資料庫的管理是一個非常專業的事情,對資料庫的調優、監控一般是由資料庫工程師完成,但是開發人員也經常與資料庫打交道,即使是簡單的增刪改查也是有很多竅門,這裡,一起來聊聊資料庫中很容易忽略的問題。
欄位長度省著點用
先說說我們常用的型別的儲存長度:
列型別 | 儲存長度 |
---|---|
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