mysql 索引_MySQL之索引
索引查找算法BTREE
BTREE查找算法演變B-TREE :普通 BTREE,平衡多路查找樹(B-Tree)B+TREE :葉子節(jié)點(diǎn)雙向指針B++TREE(B*TREE):枝節(jié)點(diǎn)的雙向指針普通B-TREE
增強(qiáng)版B+TREE(B*TREE)
總結(jié):從上圖看出,在B+Tree上有兩個(gè)頭指針,一個(gè)指向根節(jié)點(diǎn),另一個(gè)指向關(guān)鍵字最小的葉子節(jié)點(diǎn),而且所有葉子節(jié)點(diǎn)(即數(shù)據(jù)節(jié)點(diǎn))之間是一種鏈?zhǔn)江h(huán)結(jié)構(gòu)。B+Tree是在B-Tree基礎(chǔ)上的一種優(yōu)化,使其更適合實(shí)現(xiàn)外存儲索引結(jié)構(gòu),InnoDB存儲引擎就是用B+Tree實(shí)現(xiàn)其索引結(jié)構(gòu)。從上圖中的B-Tree結(jié)構(gòu)圖中可以看到每個(gè)節(jié)點(diǎn)中不僅包含數(shù)據(jù)的key值,還有data值。而每一個(gè)頁的存儲空間是有限的,如果data數(shù)據(jù)較大時(shí)將會導(dǎo)致每個(gè)節(jié)點(diǎn)(即一個(gè)頁)能存儲的key的數(shù)量很小,當(dāng)存儲的數(shù)據(jù)量很大時(shí)同樣會導(dǎo)致B-Tree的深度較大,增大查詢時(shí)的磁盤I/O次數(shù),進(jìn)而影響查詢效率。在B+Tree中,所有數(shù)據(jù)記錄節(jié)點(diǎn)都是按照鍵值大小順序存放在同一層的葉子節(jié)點(diǎn)上,而非葉子節(jié)點(diǎn)上只存儲key值信息,這樣可以大大加大每個(gè)節(jié)點(diǎn)存儲的key值數(shù)量,降低B+Tree的高度。而BTree,這個(gè)是以B+Tree為基礎(chǔ),在非葉子結(jié)點(diǎn)(枝節(jié)點(diǎn))上增加了鏈表指針,BTree的空間利用率更高。
MySQL中如何使用BTREE
1 聚簇索引
聚簇索引也叫集群索引,聚集索引。它不是一種單獨(dú)的索引類型,而是一種數(shù)據(jù)存儲方式。Innodb的聚簇索引實(shí)際上在同一個(gè)結(jié)構(gòu)中保存了B*Tree索引和數(shù)據(jù)行。當(dāng)表有聚簇索引時(shí),數(shù)據(jù)行實(shí)際上存儲在索引的葉子節(jié)點(diǎn)中。聚簇的意思是表示數(shù)據(jù)行和相鄰的鍵值緊湊地存儲在一起。一個(gè)表只能有一個(gè)聚簇索引。也就是按照每張表的主鍵構(gòu)成一棵B+樹,葉子節(jié)點(diǎn)中存放整張表的行記錄數(shù)據(jù),也將聚集索引的葉子節(jié)點(diǎn)成為數(shù)據(jù)頁,每個(gè)數(shù)據(jù)頁之間通過一個(gè)雙向鏈表來進(jìn)行鏈接。數(shù)據(jù)頁存放的是每行的所有記錄,非數(shù)據(jù)頁存放的是鍵值和指向數(shù)據(jù)頁的偏移量。它可以在葉子節(jié)點(diǎn)直接找到數(shù)據(jù),且對于主鍵的排序查找和范圍查找速度非常快,因?yàn)榫奂饕沁壿嬌线B續(xù)的。比如查詢后10條數(shù)據(jù),由于B+樹索引是雙向鏈表,可以很快找到隨后一個(gè)數(shù)據(jù)頁,然后取出最后的10條數(shù)據(jù)。
①前提條件
1.如果表中設(shè)置了主鍵(例如ID列),自動(dòng)根據(jù)ID列生成索引樹。2.如果沒有設(shè)置主鍵,自動(dòng)選擇第一個(gè)唯一鍵的列作為聚簇索引3.如果沒有唯一鍵,自動(dòng)生成隱藏的聚簇索引。4.在建表時(shí),推薦創(chuàng)建主鍵為數(shù)字自增列。②功能
1.錄入數(shù)據(jù)時(shí),按照聚簇索引組織存儲數(shù)據(jù),在磁盤上有序存儲數(shù)據(jù)行。2.加速查詢(基于ID作為條件的判斷查詢)。③聚簇索引的B*Tree構(gòu)建過程
a. 葉子節(jié)點(diǎn):存儲數(shù)據(jù)行時(shí)就是有序的,直接將數(shù)據(jù)行的page作為葉子節(jié)點(diǎn)(相鄰的葉子結(jié)點(diǎn),有雙向指針)b. 枝節(jié)點(diǎn) :提取葉子節(jié)點(diǎn)ID的范圍+指針,構(gòu)建枝節(jié)點(diǎn)(相鄰枝節(jié)點(diǎn),有雙向指針)c. 根節(jié)點(diǎn) :提取枝節(jié)點(diǎn)的ID的范圍+指針,構(gòu)建根節(jié)點(diǎn)2 輔助索引
輔助索引需要人為創(chuàng)建輔助索引,將經(jīng)常作為查詢條件的列創(chuàng)建輔助索引,起到加速查詢的效果。也稱非聚集索引,按照每張表創(chuàng)建的索引列創(chuàng)建一棵B+樹,葉子節(jié)點(diǎn)并不包含行記錄的全部數(shù)據(jù)。葉子節(jié)點(diǎn)包含鍵值 和 書簽,書簽用來告訴InnoDB存儲引擎在哪可以找到與索引對應(yīng)的行數(shù)據(jù),每張表可以有多個(gè)輔助索引。如果某個(gè)查詢是通過輔助索引查找數(shù)據(jù)的,則查找過程為:先遍歷輔助索引并找到葉節(jié)點(diǎn)找到指針獲取主鍵索引的主鍵,然后通過主鍵索引找到對應(yīng)的頁從而找到一個(gè)完整的行記錄。注:沒執(zhí)行一次查詢就是一次IO,比如 輔助索引樹高度為3,聚集索引樹高度為2,則通過輔助索引查詢數(shù)據(jù)時(shí)就要進(jìn)行3+2次邏輯IO最終得到一個(gè)數(shù)據(jù)頁。
輔助索引的B*Tree 構(gòu)建過程
a. 葉子節(jié)點(diǎn):提取主鍵(ID)+輔助索引列,按照輔助索引列進(jìn)行從小到大排序后,生成葉子節(jié)點(diǎn)。(多個(gè)輔助索引列,以最左邊的列為標(biāo)準(zhǔn)。相鄰的葉子結(jié)點(diǎn),有雙向指針。)b. 枝節(jié)點(diǎn) :提取葉子節(jié)點(diǎn)輔助索引列的范圍+指針,構(gòu)建枝節(jié)點(diǎn)(相鄰枝節(jié)點(diǎn),有雙向指針)c. 根節(jié)點(diǎn) :提取枝節(jié)點(diǎn)的輔助索引列的范圍+指針,構(gòu)建根節(jié)點(diǎn)輔助索引查詢過程:
# 按照輔助索引列,作為查詢條件時(shí)。1. 查找輔助索引樹,得到ID值2. 拿著ID值回表(聚簇索引)查詢①單列索引
只拿一個(gè)非主鍵列來創(chuàng)建索引,如下:
# 單列輔助索引 select * from test.t100w where k2='780P' # 優(yōu)化方式: alter table 表名 add index 索引名(列名); mysql> alter table t100w add index idx_k2(k2);②聯(lián)合索引
# 使用多個(gè)非主鍵列創(chuàng)建輔助索引mysql> alter table t100w add index idx_k1_num(k1,num);③前綴索引
列值長度越長,數(shù)據(jù)量大的話,會影響到索引高度,需要使用前綴索引,也就是截取列值的前綴生成新的索引以提高效率。
# 判斷前綴長度多少合適:截取字符串之后得到的總記錄數(shù)越接近截取之前的越好,說明前綴的唯一性高!select count(distinct(left(name,5))) from city ;select count(distinct name) from city ;# 創(chuàng)建前綴索引mysql> alter table city add index idx_n(name(5)); # 刪除索引mysql> alter table city drop index idx_n;關(guān)于索引的相關(guān)問題
1 回表問題
# 關(guān)于輔助索引回表是什么?回表會帶來什么問題?怎么減少回表?a. 回表:按照輔助索引列作為查詢條件時(shí),先查找輔助索引樹,再到聚簇索引樹查找數(shù)據(jù)行的過程。b. 影響:IO量多、IO次數(shù)多、隨機(jī)IO會增多c. 減少回表: 1. 輔助索引能夠完全覆蓋查詢結(jié)果,可以使用聯(lián)合索引。 2. 盡量讓查詢條件精細(xì)化,盡量使用唯一值多的列作為查詢條件 3. 優(yōu)化器:MRR(Multi-Range-Read), 錦上添花的功能。 mysql> select @@optimizer_switch; mysql> set global optimizer_switch='mrr=on';功能:(1)輔助索引查找后得到ID值,進(jìn)行自動(dòng)排序(2)一次性回表,很有可能受到B+TREE中的雙向指針的優(yōu)化查找。2 索引樹高度的影響因素
a. 高度越低越好b. 數(shù)據(jù)行越多,高度越高。 1. 分區(qū)表。一個(gè)實(shí)例里管理。基本不再使用了! 2. 按照數(shù)據(jù)特點(diǎn),進(jìn)行歸檔表。 3. 分布式架構(gòu)。針對海量數(shù)據(jù)、高并發(fā)業(yè)務(wù)主流方案。 4. 在設(shè)計(jì)方面,滿足三大范式。c. 主鍵規(guī)劃:長度過長。 1. 主鍵,盡量使用自增數(shù)字列。 d. 列值長度越長,數(shù)據(jù)量大的話,會影響到高度。 1. 使用前綴索引 比如列值長100字符,那么只取前10個(gè)字符,構(gòu)建索引樹。 e. 數(shù)據(jù)類型的選擇。 選擇合適的、簡短的數(shù)據(jù)類性。 例如: 1. 存儲人的年齡 ,使用 tinyint 和 char(3)哪個(gè)好一些 2. 存儲人名,char(20)和varchar(20)的選擇哪一個(gè)好。 a. 站在數(shù)據(jù)插入性能角度思考,應(yīng)該選:char b. 從節(jié)省空間角度思考,應(yīng)該選:varchar c. 從索引樹高度的角度思考,應(yīng)該選:varchar結(jié)論:建議使用varchar類型存儲變長列值創(chuàng)建索引
查詢表索引
mysql> desc city;+-------------+----------+------+-----+---------+----------------+| Field | Type | Null | Key | Default | Extra |+-------------+----------+------+-----+---------+----------------+| ID | int(11) | NO | PRI | NULL | auto_increment || Name | char(35) | NO | MUL | | || CountryCode | char(3) | NO | UK | | || District | char(20) | NO | | | || Population | int(11) | NO | | 0 | |+-------------+----------+------+-----+---------+----------------+5 rows in set (0.00 sec) PK --> 主鍵(聚簇索引) MUL --> 輔助索引 UK --> 唯一索引 mysql> show index from city;+-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |+-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+| city | 0 | PRIMARY | 1 | ID | A | 4188 | NULL | NULL | | BTREE | | || city | 1 | CountryCode | 1 | CountryCode | A | 232 | NULL | NULL | | BTREE | | || city | 1 | idx_name | 1 | Name | A | 3554 | 5 | NULL | | BTREE | | |+-------+------------+-------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+ # Cardinality值越大,索引優(yōu)先級越高。創(chuàng)建索引
# 單列輔助索引 select * from test.t100w where k2='780P'; # 該表沒有索引,大量數(shù)據(jù)查詢耗時(shí)極大,需要優(yōu)化! 優(yōu)化方式:語法:alter table 表名 add index 索引名(列名); alter table t100w add index idx_k2(k2); # 聯(lián)合索引創(chuàng)建 mysql> alter table t100w add index idx_k1_num(k1,num); # 前綴索引創(chuàng)建# 判斷前綴長度多少合適:select count(distinct(left(name,5))) from city ;select count(distinct name) from city ;# 創(chuàng)建前綴索引mysql> alter table city add index idx_n(name(5)); # 刪除索引alter table city drop index idx_n;執(zhí)行計(jì)劃獲取和分析
1 執(zhí)行計(jì)劃工具
# 獲取語句的執(zhí)行計(jì)劃工具 explain des# 使用方法 :mysql> desc select * from city where countrycode='CHN';mysql> explain select * from city where countrycode='CHN';+----+-------------+-------+------------+------+---------------+-------------+---------+-------+------+----------+-------+| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |+----+-------------+-------+------------+------+---------------+-------------+---------+-------+------+----------+-------+| 1 | SIMPLE | city | NULL | ref | CountryCode | CountryCode | 3 | const | 363 | 100.00 | NULL |+----+-------------+-------+------------+------+---------------+-------------+---------+-------+------+----------+-------+2 執(zhí)行計(jì)劃信息
table :此次查詢訪問的表type :索引查詢的類型(ALL、index、range、ref、eq_ref、const(system)、NULL)possible_keys :可能會應(yīng)用的索引key : 最終選擇的索引key_len :索引覆蓋長度,主要是用來判斷聯(lián)合索引應(yīng)用長度。rows :需要掃描的行數(shù)Extra :額外信息3 Type信息詳解
代價(jià)從高到低!
ALL
index
range
從這里開始,我們可以接受這些類型的索引查詢,但是無法容忍上述兩種!
# 索引范圍掃描# 會受到:B+TREE額外優(yōu)化,葉子節(jié)點(diǎn)雙向指針# >、=、<=、in、or、between and、likemysql> desc select * from city where id<10;mysql> desc select * from city where countrycode like 'CH%';+----+-------------+-------+------------+-------+---------------+-------------+---------+------+------+----------+-----------------------+| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |+----+-------------+-------+------------+-------+---------------+-------------+---------+------+------+----------+-----------------------+| 1 | SIMPLE | city | NULL | range | CountryCode | CountryCode | 3 | NULL | 397 | 100.00 | Using index condition |+----+-------------+-------+------------+-------+---------------+-------------+---------+------+------+----------+-----------------------+1 row in set, 1 warning (0.00 sec) # 這種情況下,主鍵索引性能還可以,如果查詢條件是輔助索引,就會牽扯到回表次數(shù)問題而導(dǎo)致性能較低。 # 以下兩種查詢,大幾率受不到葉子節(jié)點(diǎn)雙向指針優(yōu)化。# 他會遍歷兩個(gè)值之間的數(shù)據(jù),而這種遍歷是沒有必要的!mysql> desc select * from city where countrycode in ('CHN','USA');mysql> desc select * from city where countrycode='CHN' or countrycode='USA'; # 建議:如果查詢列重復(fù)值少的話,我們建議改寫為 union all (2-3個(gè),如果超過50%,那就沒什么卵用了!)desc select * from city where countrycode='CHN'union allselect * from city where countrycode='USA';+----+-------------+-------+------------+------+---------------+-------------+---------+-------+------+----------+-------+| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |+----+-------------+-------+------------+------+---------------+-------------+---------+-------+------+----------+-------+| 1 | PRIMARY | city | NULL | ref | CountryCode | CountryCode | 3 | const | 363 | 100.00 | NULL || 2 | UNION | city | NULL | ref | CountryCode | CountryCode | 3 | const | 274 | 100.00 | NULL |+----+-------------+-------+------------+------+---------------+-------------+---------+-------+------+----------+-------+2 rows in set, 1 warning (0.00 sec)ref
?
eq_ref
const(system)
NULL
總結(jié)
通常最常見的執(zhí)行計(jì)劃類型是:range、ref、eq_ref。如果出現(xiàn)index或者all的情況,那就可能涉及到改寫sql查詢語句,或者得找業(yè)務(wù)溝通查詢條件了。總結(jié)
以上是生活随笔為你收集整理的mysql 索引_MySQL之索引的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: struts2访问jsp页面404
- 下一篇: linux cmake编译源码,linu