MySQL字首索引和索引選擇性
MySQL字首索引和索引選擇性
有時候需要索引很長的字元列,這會讓索引變得大且慢。通常可以索引開始的部分字元,這樣可以大大節約索引空間,從而提高索引效率。但這樣也會降低索引的選擇性。索引的選擇性是指不重複的索引值(也稱為基數,cardinality)和資料表的記錄總數的比值,範圍從1/#T到1之間。索引的選擇性越高則查詢效率越高,因為選擇性高的索引可以讓MySQL在查詢時過濾掉更多的行。唯一索引的選擇性是1,這是最好的索引選擇性,效能也是最好的。
一般情況下某個字首的選擇性也是足夠高的,足以滿足查詢效能。對於BLOB,TEXT,或者很長的VARCHAR型別的列,必須使用字首索引,因為MySQL不允許索引這些列的完整長度。
訣竅在於要選擇足夠長的字首以保證較高的選擇性,同時又不能太長(以便節約空間)。字首應該足夠長,以使得字首索引的選擇性接近於索引的整個列。換句話說,字首的”基數“應該接近於完整的列的”基數“。
為了決定字首的合適長度,需要找到最常見的值的列表,然後和最常見的字首列表進行比較。下面的示例是mysql官方提供的示例資料庫
下載地址如下:
在示例資料庫sakila中並沒有合適的例子,所以從表city中生成一個示例表,這樣就有足夠資料進行演示:
mysql> select database();
+------------+
| database() |
+------------+
| sakila |
+------------+
1 row in set (0.00 sec)
mysql> create table city_demo (city varchar(50) not null);
Query OK, 0 rows affected (0.02 sec)
mysql> insert into city_demo (city) select city from city;
Query OK, 600 rows affected (0.08 sec)
Records: 600 Duplicates: 0 Warnings: 0
mysql> insert into city_demo (city) select city from city_demo;
Query OK, 600 rows affected (0.07 sec)
Records: 600 Duplicates: 0 Warnings: 0
mysql> update city_demo set city = ( select city from city order by rand() limit 1);
Query OK, 1199 rows affected (0.95 sec)
Rows matched: 1200 Changed: 1199 Warnings: 0
mysql>
因為這裡使用了rand()函式,所以你的資料會與我的不同,當然那不影響聰明的你。
首先找到最常見的城市列表:
mysql> select count(*) as cnt, city from city_demo group by city order by cnt desc limit 10;
+-----+--------------+
| cnt | city |
+-----+--------------+
| 8 | Garden Grove |
| 7 | Escobar |
| 7 | Emeishan |
| 6 | Amroha |
| 6 | Tegal |
| 6 | Lancaster |
| 6 | Jelets |
| 6 | Ambattur |
| 6 | Yingkou |
| 6 | Monclova |
+-----+--------------+
10 rows in set (0.01 sec)
mysql>
注意到查詢結果,上面每個值都出現了6-8次。現在查詢到頻繁出現的城市字首。先從3個字首字母開始,然後4個,5個,6個:
mysql> select count(*) as cnt,left(city,3) as pref from city_demo group by pref order by cnt desc limit 10;
+-----+------+
| cnt | pref |
+-----+------+
| 25 | San |
| 15 | Cha |
| 12 | Bat |
| 12 | Tan |
| 11 | al- |
| 11 | Gar |
| 11 | Yin |
| 10 | Kan |
| 10 | Sou |
| 10 | Bra |
+-----+------+
10 rows in set (0.00 sec)
mysql> select count(*) as cnt,left(city,4) as pref from city_demo group by pref order by cnt desc limit 10;
+-----+------+
| cnt | pref |
+-----+------+
| 12 | San |
| 10 | Sout |
| 8 | Chan |
| 8 | Sant |
| 8 | Gard |
| 7 | Emei |
| 7 | Esco |
| 6 | Ying |
| 6 | Amro |
| 6 | Lanc |
+-----+------+
10 rows in set (0.01 sec)
mysql> select count(*) as cnt,left(city,5) as pref from city_demo group by pref order by cnt desc limit 10;
+-----+-------+
| cnt | pref |
+-----+-------+
| 10 | South |
| 8 | Garde |
| 7 | Emeis |
| 7 | Escob |
| 6 | Amroh |
| 6 | Yingk |
| 6 | Moncl |
| 6 | Lanca |
| 6 | Jelet |
| 6 | Tegal |
+-----+-------+
10 rows in set (0.01 sec)
mysql> select count(*) as cnt,left(city,6) as pref from city_demo group by pref order by cnt desc limit 10;
+-----+--------+
| cnt | pref |
+-----+--------+
| 8 | Garden |
| 7 | Emeish |
| 7 | Escoba |
| 6 | Amroha |
| 6 | Yingko |
| 6 | Lancas |
| 6 | Jelets |
| 6 | Tegal |
| 6 | Monclo |
| 6 | Ambatt |
+-----+--------+
10 rows in set (0.00 sec)
mysql>
透過上面改變不同字首長度發現,當字首長度為6時,這個字首的選擇性就接近完整咧的選擇性了。甚至是一樣的。
當然還有另外更方便的方法,那就是計算完整列的選擇性,並使其字首的選擇性接近於完整列的選擇性。下面顯示如何計算完整列的選擇性:
mysql> select count(distinct city) / count(*) from city_demo;
+---------------------------------+
| count(distinct city) / count(*) |
+---------------------------------+
| 0.4283 |
+---------------------------------+
1 row in set (0.05 sec)
mysql>
可以在一個查詢中針對不同字首長度的選擇性進行計算,這對於大表非常有用,下面給出如何在同一個查詢中計算不同字首長度的選擇性:
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>
可以看見當索引字首為6時的基數是0.4267,已經接近完整列選擇性0.4283。
在上面的示例中,已經找到了合適的字首長度,下面建立字首索引:
mysql> alter table city_demo add key (city(6));
Query OK, 0 rows affected (0.19 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql>
mysql> explain select * from city_demo where city like 'Jinch%';
+----+-------------+-----------+-------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------+-------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | city_demo | range | city | city | 20 | NULL | 2 | Using where |
+----+-------------+-----------+-------+---------------+------+---------+------+------+-------------+
1 row in set (0.00 sec)
mysql>
可以看見正確使用剛建立的索引。
字首索引是一種能使索引更小,更快的有效辦法,但另一方面也有其缺點:
mysql無法使用其字首索引做ORDER BY和GROUP BY,也無法使用字首索引做覆蓋掃描。
參考資料
<<高效能MySQL第三版>>
About Me
.............................................................................................................................................
● 本文作者:小麥苗,部分內容整理自網路,若有侵權請聯絡小麥苗刪除
● 本文在itpub(http://blog.itpub.net/26736162/abstract/1/)、部落格園(http://www.cnblogs.com/lhrbest)和個人微信公眾號(xiaomaimiaolhr)上有同步更新
● 本文itpub地址:http://blog.itpub.net/26736162/abstract/1/
● 本文部落格園地址:http://www.cnblogs.com/lhrbest
● 本文pdf版、個人簡介及小麥苗雲盤地址:http://blog.itpub.net/26736162/viewspace-1624453/
● 資料庫筆試面試題庫及解答:http://blog.itpub.net/26736162/viewspace-2134706/
● DBA寶典今日頭條號地址:
.............................................................................................................................................
● QQ群號:230161599(滿)、618766405
● 微信群:可加我微信,我拉大家進群,非誠勿擾
● 聯絡我請加QQ好友(646634621),註明新增緣由
● 於 2017-09-01 09:00 ~ 2017-09-30 22:00 在魔都完成
● 文章內容來源於小麥苗的學習筆記,部分整理自網路,若有侵權或不當之處還請諒解
● 版權所有,歡迎分享本文,轉載請保留出處
.............................................................................................................................................
● 小麥苗的微店:
● 小麥苗出版的資料庫類叢書:http://blog.itpub.net/26736162/viewspace-2142121/
.............................................................................................................................................
使用微信客戶端掃描下面的二維碼來關注小麥苗的微信公眾號(xiaomaimiaolhr)及QQ群(DBA寶典),學習最實用的資料庫技術。
小麥苗的微信公眾號 小麥苗的DBA寶典QQ群1 小麥苗的DBA寶典QQ群2 小麥苗的微店
.............................................................................................................................................
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/26736162/viewspace-2144621/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- MySQL 字串索引和字首索引MySql字串索引
- 本地索引、全域性索引、字首索引、非字首索引索引
- mysql索引之字首索引MySql索引
- mysql聯合索引的選擇性MySql索引
- mysql建立字首索引MySql索引
- MySQL 字首索引——讓索引減負狂奔MySql索引
- 如何選擇普通索引和唯一索引《死磕MySQL系列 五》索引MySql
- 分割槽表全域性索引與本地索引的選擇索引
- mysql字首索引是什麼MySql索引
- MySQL查詢索引的選擇性、索引欄位、註釋等基本資訊的SQLMySql索引
- MySQL 查詢索引的選擇性、索引欄位、註釋等基本資訊的SQLMySql索引
- MySQL索引選擇及規則整理MySql索引
- pandas索引和選擇資料索引
- 表資料量影響MySQL索引選擇MySql索引
- MySQL innodb如何選擇一個聚簇索引MySql索引
- MySQL 選錯索引MySql索引
- [Mysql]索引選型MySql索引
- Elasticsearch 中為什麼選擇倒排索引而不選擇 B 樹索引Elasticsearch索引
- mysql 字首索引 的一些介紹MySql索引
- 索引的選擇原則索引
- 資料庫系列:字首索引和索引長度的取捨資料庫索引
- Oracle全域性索引和本地索引Oracle索引
- MySQL資料庫索引選擇使用B+樹MySql資料庫索引
- 面試 (MySQL 索引為啥要選擇 B+ 樹)面試MySql索引
- mysql索引為啥要選擇B+樹 (下)MySql索引
- mysql索引為啥要選擇B+樹 (上)MySql索引
- MySQL 唯一索引和普通索引MySql索引
- 資料庫索引選擇策略資料庫索引
- MySQL學習之影響優化器選擇索引因素MySql優化索引
- MySQL 聚簇索引 和覆蓋索引MySql索引
- 全域性索引和本地索引的比較索引
- 分割槽索引和全域性索引(轉載)索引
- MySQL的字首索引及Oracle的類似實現MySql索引Oracle
- MySQL 選錯索引的原因?MySql索引
- [轉]Oracle分割槽索引--本地索引和全域性索引比較Oracle索引
- Oracle分割槽索引--本地索引和全域性索引比較(轉)Oracle索引
- 全域性分割槽索引和區域性分割槽索引索引
- 組合索引的選擇原則索引