mysql知識盤點【壹】_SQL優化
簡單一點,上來就說說資料庫優化。本文都是基於mysql資料庫的優化建議。分為四個方面:索引優化、sql優化、建表優化和引數優化。
索引優化
首先介紹下索引。索引是資料庫中一個排序的資料結構,用於快速查詢和更新資料。根據結構形式可分為B樹索引(B-tree)、雜湊索引(hash)、空間索引(R-tree)和全文索引(full-text)。
mysql有兩大資料庫引擎,分別為MYISAM和innodb,其中innodb支援事務。下面說說innodb的索引結構:索引鍵值的邏輯順序和索引鎖服務的表相應的物理順序相同(即聚集索引,Cluster index),也就是說,資料和索引(B+樹)在一起,記錄被真實儲存在索引葉子中。如下圖所示:
需要注意的是,mysql索引僅支援最左字首原則(比如 LIKE 'xx%'),同時不支援函式索引和使用IN範圍查詢。
索引使用還有如下原則:
1.索引欄位不要超過5個,單表索引儘量不超過5個;
2.ORDER BY、GROUP BY和DISTINCT欄位放在複合索引的後面,即複合索引前面欄位用於等值查詢,後面欄位用於判斷;
3.UPDATE語句根據WHERE條件增加索引;
4.把範圍條件放在符合索引的最後,因為BETWEEN、<、<=、>、>=會導致後面條件用不了索引;
5.資料區分度不大的欄位不宜使用索引;
sql優化
ORDER BY、GROUP BY
1.儘量對較少的行排序;
2.如果連線多張表。ORDER BY的列應該屬於連線順序第一張表;
3.ORDER BY、GROUP BY的列儘量都在第一張表中;
4.保證索引列和ORDER BY列相同,且順序一致;
5.增加read_rnd_buffer_size(MySQL的隨機讀緩衝區大小)
分頁語句優化
mysql的分頁語句為:
select * from table where col = xxx limit M , N;
越往後翻頁速度越慢,因為mysql會讀取M+N條資料,M越大效能越差。可考慮改為如下方式:
select t1.* from table t1 ,
(select col
where t1.col = t2.col ;
或當條件是主鍵id時:
select * from table where id>=2345 limit 11;
select * from table where id>=(select id from table limit 10000,1) limit 10;
select * from table inner join (select id from table limit 10000,10) using (id);
子查詢優化
當有如下sql:
select first_name from employee where emp_no IN (
select emp_no from salary where salary = 5000);
這樣會遍歷employee表每條記錄帶入子查詢中,可改為:
select first_name from emplyee emp ,
(select emp_no from salary where salary = 5000) sal
where emp.emp_no = sal.emp_no;
其他一些sql建議
儘量不用select *
1.減少表變化時的影響;
2.可以使用到covering index;
3.select/join減少硬碟臨時表生成
OR條件改為IN
OR時間複雜度:O(n);IN時間複雜度:O(Log n)。[n最好小於200條]
避免負向查詢NOT、!和<>
1.不能使用索引
2.很可能全表掃描
數值比對
1.數字對數字,字元對字元;
2.數值和字元比較先轉換為雙精度進行比對;
3.字元和數字比較:字元轉數值,不會使用索引;
建表優化
建表前首先對資料量預估,一年內的單表資料量純int不超1000W,含char不超500W。如果會超過,建議考慮分表,可基於userid、date或area合理實現。
建議單庫不超過300-400個表,表的欄位少而精,好處IO高效,遍歷快,修復快,提高併發,alter快。單表字段數控制在20-50個,不超50個純INT,20個CHAR(10)。
避免使用null欄位:1.很難查詢優化;2.null加索引,需要額外空間;3.含null複合索引無效。儘量不用TEXT/BLOB資料型別:強制生成硬碟臨時表;浪費空間,可想辦法拆分欄位到單獨的表。
儘量不用外來鍵:1.額外開銷;2.逐行操作;3.高併發容易死鎖。
數字型的索引比字串型快:更高效,查詢更快,空間更小。
引數優化
innodb_buffer_pool_size
innodb引擎緩衝池大小,主要快取了索引和資料。如果sql查詢的資料在快取中已快取,則不需要從磁碟中讀取,建議設定為主機記憶體的70-80%。
Innodb緩衝池
快取了行資料、索引、插入緩衝和鎖等。innodb還使用緩衝池幫助延遲寫入,這樣就可以合併多個寫入操作一起順序寫回。
innodb_log_file_size
日誌組裡日誌檔案大小。建議256M或更大,預設5M。
innodb_flush_log_at_trx_commit
預設1。設為2時,每個事務提交時日誌緩衝被寫到檔案上,但不對日誌檔案做刷盤操作。刷盤每秒發生一次。建議設2。
sysc_binlog
預設0。不實時將二進位制日誌中的語句刷盤。設定大於1時實時。建議設0。
tmp_table_size
決定內部記憶體臨時表最大值,每個執行緒都會分配,如果記憶體臨時表超過限制,mysql就會把它轉為基於磁碟的MYISAM表。GROUP BY和DISTINCT等不能走索引的sql會總臨時表,適當加大tmp_table_size和max_heap_table_size的值。
table_open_cache
指定表快取記憶體大小。每當mysql訪問一張表,如果表緩衝區還有空間,該表就被開啟放入其中,這樣可以加快訪問表內容。
query_cache_size
控制mysql query cache的大小。如果mysql開啟query cache,在執行每個query時會先鎖住query cache,然後判斷是否存在query cache,如果存在則返回;不存在則進行引擎查詢。同時insert、update和delete會將query cache失效掉,所以適合寫少讀多的情況。