1. 程式人生 > >mysql知識盤點【壹】_SQL優化

mysql知識盤點【壹】_SQL優化

簡單一點,上來就說說資料庫優化。本文都是基於mysql資料庫的優化建議。分為四個方面:索引優化、sql優化、建表優化和引數優化。

索引優化

首先介紹下索引。索引是資料庫中一個排序的資料結構,用於快速查詢和更新資料。根據結構形式可分為B樹索引(B-tree)、雜湊索引(hash)、空間索引(R-tree)和全文索引(full-text)。

mysql有兩大資料庫引擎,分別為MYISAM和innodb,其中innodb支援事務。下面說說innodb的索引結構:索引鍵值的邏輯順序和索引鎖服務的表相應的物理順序相同(即聚集索引,Cluster index),也就是說,資料和索引(B+樹)在一起,記錄被真實儲存在索引葉子中。如下圖所示:

1

需要注意的是,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

from table where col  = xxx limit M , N) t2

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失效掉,所以適合寫少讀多的情況。