** mysql 的索引的構成以及優化**
(B+樹 網上來,但并不是索引的實現,索引是用雙向鏈表)
InnoDB存儲引擎表示索引組織表,即表中數據按照主鍵順序存放。聚集索引就是按照每張表的主鍵構造一棵B+樹,葉子節點存放的是整張表的行記錄數據。這種葉子節點也可以稱為數據頁。聚集索引的這個特性決定了索引組織表中的數據也是索引的一部分。每個數據頁都是通過一個雙向鏈表來鏈接的。
數據頁只能按照一棵b+樹來排序。
在多數情況下,查詢優化器傾向于采用聚集索引,因為該葉子節點中包含了數據。定義了數據的邏輯順序,聚集索引能很快的對某一范圍值進行查詢。查詢優化器能夠快速發現某一段范圍的數據頁需要掃描。
如果聚集索引必須按照特定順序存放物理記錄,則維護成本顯得非常高。這也決定了聚集索引的存儲并不是物理上連續的,而是邏輯連續的。頁通過雙向鏈表鏈接,頁按照主鍵的順序排序的。
因為是雙向鏈表的情況,用戶可以快速的找到最好的一個數據頁。查找某一范圍的數據,只要通過節點的上層中間節點就可以得到頁的范圍。
輔助索引也叫非聚集索引,葉子節點并不包括含行數據,而是存了一個書簽,告訴我們到哪里去找相應行數據的聚集索引鍵。
如果在一棵高度為3的輔助索引中查找數據,需要遍歷3次輔助索引,還要根據書簽查詢聚集索引的地址3次,一共6次io操作,從而得到最終的一個數據頁。
mysql 可以通過SHOW Index 來查看表中的索引的信息。查詢結果中有一個非常關鍵的值Cardinality ,這個是索引中唯一值的估計值如果非常小,就要考慮是否刪除該索引。
覆蓋索引,就是可以從輔助索引中自己得到查詢的記錄,而不去查詢聚集索引。覆蓋索引本身并不會存儲行數據,自然比聚集索引要消耗小。
MySQL的子查詢一直是以性能差著稱的,針對select子查詢,
select * from country where city='hangzhou' and country.code in(select * ......)
其實這首先會把符合的數據過了,對每個數據都與內表city進行一次select查詢,性能低下。
其實我們可以改成
select .....as a join(select .....) as b on a.code =b.country
** 索引優化**
like'%xxx%' 是不會用到索引的,like 'xxx%'可以
但如果select id 這個id是聚集索引主鍵,就用的了覆蓋索引
limit 分頁
select * from text order by id limit 99999,10;
優化:
select * from text where id >=100000 order by id limit 10;
count(輔助索引)<count(*)
count 是很耗時的,對于innDB內部是沒有計數器的,其實可以加一個列計數。
-索引適用場景:
1. 經常order by 、group by distinct 后面的字段
2. 在union等集合操作的結果集字段
3. 經常查詢的字段
4. 經常用在表連接上的字段
5. 很少被更新的字段
6.均勻分布的不用索引
- 索引失效場景:
1. 如果條件中有or,即是其中有條件帶索引也不生效
2. like 查詢是以%開頭
3. 如果類型是字符串,則一定要在條件中使用引號引起來,否則不會使用索引
4. 如果mysql估計使用全表掃描要比使用索引快,則不使用索引(當取出的數據量超過數據的20%)
5.字段用了函數是不能用索引的
此外,查看索引的使用情況
show status like ‘Handler_read%';
大家可以注意:
handler_read_key:這個值越高越好,越高表示使用索引查詢到的次數
handler_read_rnd_next:這個值越高,說明查詢低效