晚上睡不著,腦子裡總想著一些問題,試著寫一寫對於SQL查詢最佳化的見解。
首先,資料庫有自己的查詢最佳化器,執行一條查詢SQL最佳化器會選擇最優的方式(不走索引、走索引、走哪個索引),
所以索引不是越多越好,因為建立索引需要成本,提高索引命中率是最佳化SQL的關鍵。
索引分為主鍵索引和普通索引,在Mysql資料庫的InnoDB下,索引的結構是一顆B+樹(非葉子節點存放索引,葉子節點存放資料、所有葉子節點組成一個雙向連結串列),
每一張表都有一個主鍵索引,意味著有一個主鍵索引的B+樹,建立一個普通索引同時會建立一個該索引的B+樹,和主鍵索引的不同點是,普通索引的葉子節點存放的是(索引列+主鍵ID),
如果查詢最佳化器命中主鍵索引,直接透過主鍵索引查詢出資料
如果查詢最佳化器命中該索引,查詢資料列被索引覆蓋了則直接返回,如果沒有覆蓋,則需要透過主鍵ID去查詢主鍵索引的資料,這個過程稱為回表。
如果沒有命中索引,會遍歷主鍵索引的葉子節點(全表掃描)
如何選擇合適的索引列?
適合作為索引的列:查詢條件、排序條件
不適合做索引的列:沒有作為查詢條件、唯一性太差(走索引效率不高)、更新頻繁(索引維護成本高)
組合索引的順序選擇:根據條件使用熱度來排序
如何避免索引失效?
遵循最左字首法則,比如一個組合索引(abc),要命中索引查詢條件的組合有(a、ab、abc)
避免在索引列上使用函式,這樣會使索引失效
避免使用全模糊查詢
避免使用 is (not) null
。。。。?
減少網路IO、減少回表?
禁止使用 *
連表查詢?
連表條件建立索引
小表驅動大表
業務最佳化?
舉例,深分頁可以把上一頁最大ID作為Where條件,減少掃描範圍
其他?
拉寬表,允許一些冗餘欄位,減少表連線
分庫分表