高性能索引设计
索引的優(yōu)點(diǎn)
- 減少了服務(wù)器需要掃描的數(shù)據(jù)量
- 幫助服務(wù)器避免排序和臨時(shí)表
- 將隨機(jī)I/O變成順序I/O
索引的類型
B-Tree索引
適用的查詢范圍:
- 全值匹配。和索引中的所有列進(jìn)行匹配。
- 匹配最左前綴。多列索引的最左前綴原則。例如一個(gè)多列索引為(A,B,C),當(dāng)你的查詢中包括A或A,B或A,B,C都可以用到索引,如果只有B,則無法用到該索引。
- 匹配列前綴。像like 'abc%'可以用到索引,而like '%abc%'就無法用到該類索引。
- 匹配范圍值。其實(shí)就是范圍查詢,但當(dāng)多列索引中有一列用到范圍查詢時(shí),那么該列后面的索引都沒法被用到。例如一個(gè)索引為(A,B,C),又一個(gè)查詢?yōu)?/span>where A=1, B>1, C=1,那么這個(gè)查詢只會(huì)用到(A,B,C)中的A,B列,C是不會(huì)被用到。
- 只訪問索引的查詢。其實(shí)就是覆蓋索引查詢。
?hash索引
哈希索引是基于哈希表實(shí)現(xiàn),在MySQL中,目前只有Memory引擎支持哈希索引。
| ? | 適用場景 | 不支持場景 |
| 哈希索引 | 只支持等值比較查詢 | 1、哈希索引的數(shù)據(jù)并不是按照索引值順序存放的,因此無法用于排序查找和范圍查找 2、不支持部分索引列按匹配查找,使用索引列的全部內(nèi)容來計(jì)算哈希值 |
高性能索引策略
1 獨(dú)立的列
索引列不能是表達(dá)式的一部分,也不能是函數(shù)的參數(shù)
2 前綴索引和索引選擇性
索引選擇性:不重復(fù)的索引值和數(shù)據(jù)表記錄總數(shù)(T)的比值,取值范圍是從1/T ~1之間。索引的選擇性越高,查詢效率越高。唯一索引的選擇性是1。
前綴索引:某個(gè)列太長,比如varchar類型很長的列,則必須使用前綴索引。關(guān)鍵在選擇足夠長的前綴保證較高的選擇性,但又不能太長。方法:找到最常見的值列表,然后和最常見的前綴列表進(jìn)行比對(duì),然后逐漸增加前綴長度,直到前綴的選擇性接近于完整列的選擇性。
| select count(distinct city) / count(*) from city_demo; mysql> select count(distinct left(city,3))/count(*) as sel3, ??? -> count(distinct left(city,4))/count(*) as sel4, ??? -> count(distinct left(city,5))/count(*) as sel5, ??? -> count(distinct left(city,6))/count(*) as sel6 ??? -> from city_demo; +--------+--------+--------+--------+ | sel3?? | sel4?? | sel5?? | sel6?? | +--------+--------+--------+--------+ | 0.3367 | 0.4075 | 0.4208 | 0.4267 | +--------+--------+--------+--------+ 1 row in set (0.01 sec) mysql> |
?
缺點(diǎn):mysql無法使用其前綴索引做ORDER BY和GROUP BY,也無法使用前綴索引做覆蓋掃描
3 多列索引
建立多列索引,那么選擇合適的順序相當(dāng)重要。對(duì)于如何選擇合適的索引順序,有一個(gè)經(jīng)驗(yàn)法則:將選擇性最高的列放到索引最前列。
4 聚簇索引
聚簇索引把數(shù)據(jù)行存儲(chǔ)在葉子頁中,一個(gè)表中只能有一個(gè)聚簇索引。InnoDB存儲(chǔ)引擎支持聚簇索引,在InnoDB中,聚簇索引其實(shí)就是主鍵索引。如果表中沒有定義主鍵,InnoDB會(huì)選擇一個(gè)唯一非空索引作為主鍵。如果沒有這樣的索引,InnoDB會(huì)隱式的定義一個(gè)主鍵來作為聚簇索引。聚簇索引的優(yōu)點(diǎn)如下:
- 可以把相關(guān)數(shù)據(jù)保存在一起。
- 數(shù)據(jù)訪問更快。
- 使用覆蓋索引掃描的查詢可以直接使用頁節(jié)點(diǎn)中的主鍵值。
如果表在設(shè)計(jì)和查詢的時(shí)候能充分利用以上特點(diǎn),將會(huì)極大提高性能。
當(dāng)然,聚簇索引也有它的缺點(diǎn):
- 聚簇索引最大限度提高了I/O密集型應(yīng)用的性能,但如果所有的數(shù)據(jù)都存放在內(nèi)存中,聚簇索引就沒有優(yōu)勢了。
- 插入速度嚴(yán)重依賴插入順序。這也是為什么InnoDB一般都會(huì)設(shè)置一個(gè)自增的int列作為主鍵。
- 更新聚簇索引的代價(jià)很高,因?yàn)闀?huì)強(qiáng)制InnoDB將每個(gè)被更新的行移到新的位置。
- 如果不按順序插入新數(shù)據(jù)時(shí),可能會(huì)導(dǎo)致"頁分裂"。
- 二級(jí)索引可能會(huì)比想象的更大。因?yàn)樵诙?jí)索引的頁子節(jié)點(diǎn)中包含了引用行的主鍵列。
- 二級(jí)索引訪問可能會(huì)需要進(jìn)行回表查詢。
5 覆蓋索引
如果一個(gè)索引包含或覆蓋所有需要查詢的字段值,我們就稱之為“覆蓋索引”。 覆蓋索引是一個(gè)非常有用的工具,可以極大的提升性能。所以可能一個(gè)索引對(duì)于某些查詢是覆蓋索引,而對(duì)于其他的查詢則不是。覆蓋索引其實(shí)是二級(jí)索引的特例,它滿足了一個(gè)特定條件:
- 索引行通常遠(yuǎn)小于數(shù)據(jù)行的大小,所以如果只需要索引,那么MySQL就會(huì)極大地減少數(shù)據(jù)訪問量。
- 因?yàn)樗饕前凑枕樞虼鎯?chǔ)的,所以對(duì)于I/O密集型的范圍查詢會(huì)比隨機(jī)從磁盤讀取每一行數(shù)據(jù)的I/O要少的多。
- 由于InnoDB的聚簇索引,所以覆蓋索引對(duì)InnoDB特別有用。
當(dāng)發(fā)起一個(gè)覆蓋查詢的時(shí)候,在Explain中的Extra列中可以看到“Using index”的信息。對(duì)于select *,沒有任何一個(gè)索引能夠覆蓋所有列。所以select * 可能會(huì)導(dǎo)致原本可以用到覆蓋索引的查詢而無法使用覆蓋索引。
6 索引條件下推(ICP)
ICP的目的是通過減少完整記錄讀取的數(shù)量來減少IO操作。在沒有ICP的時(shí)候,WHERE條件中沒有被索引用到的列的過濾是在MySQL服務(wù)層中,而有了ICP之后,這種過濾就直接在儲(chǔ)存引擎層中完成了,而且是在二級(jí)索引回表查詢前就完成了過濾,這就避免了大量數(shù)據(jù)傳輸,從而降低磁盤IO。
總結(jié)
- 上一篇: php数据访问层设计,php - Zen
- 下一篇: 天翼宽带家庭网关用户:useradmin