日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

mysql 索引_MySQL之索引

發(fā)布時(shí)間:2025/3/11 数据库 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 mysql 索引_MySQL之索引 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

索引查找算法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

# 沒有使用到索引a. 查詢條件沒建立索引# district并沒有被創(chuàng)建成輔助索引mysql> desc select * from city where district='shandong';+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+| 1 | SIMPLE | city | NULL | ALL | NULL | NULL | NULL | NULL | 4188 | 10.00 | Using where |+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+1 row in set, 1 warning (0.00 sec) b. 有索引不走# 這三種查詢不走索引mysql> desc select * from city where countrycode!='CHN';mysql> desc select * from city where countrycode not in ('CHN','USA');mysql> desc select * from city where countrycode like '%CH%';
  • index

# 全索引掃描 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 | MUL | | || District | char(20) | NO | | | || Population | int(11) | NO | | 0 | |+-------------+----------+------+-----+---------+----------------+5 rows in set (0.00 sec) mysql> desc select countrycode from city;+----+-------------+-------+------------+-------+---------------+-------------+---------+------+------+----------+-------------+| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |+----+-------------+-------+------------+-------+---------------+-------------+---------+------+------+----------+-------------+| 1 | SIMPLE | city | NULL | index | NULL | CountryCode | 3 | NULL | 4188 | 100.00 | Using index |+----+-------------+-------+------------+-------+---------------+-------------+---------+------+------+----------+-------------+1 row in set, 1 warning (0.00 sec) # 由于country是輔助索引,這里查詢會遍歷掃描索引,效率也是一種問題。
  • 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

# 輔助索引等值查詢desc 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 |+----+-------------+-------+------------+------+---------------+-------------+---------+-------+------+----------+-------+1 row in set, 1 warning (0.00 sec) #?等值查詢的代價(jià)比range就要低很多了。

?

  • eq_ref

# 多表連接查詢中,非驅(qū)動(dòng)表的連接條件是主鍵或唯一鍵時(shí)。mysql> desc select city.name,country.name from city left join country on city.countrycode=country.code where city.population<100;# 在非驅(qū)動(dòng)表country中code是主鍵,在多表連接中如果顯示未eq_ref,那就是最佳的優(yōu)化實(shí)踐,也是性能最好的一種場景。這也是多表連接中非驅(qū)動(dòng)表的優(yōu)化方向。驅(qū)動(dòng)表后續(xù)會介紹。+----+-------------+---------+------------+--------+---------------+---------+---------+------------------------+------+----------+-------------+| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |+----+-------------+---------+------------+--------+---------------+---------+---------+------------------------+------+----------+-------------+| 1 | SIMPLE | city | NULL | ALL | NULL | NULL | NULL | NULL | 4188 | 33.33 | Using where || 1 | SIMPLE | country | NULL | eq_ref | PRIMARY | PRIMARY | 3 | world.city.CountryCode | 1 | 100.00 | NULL |+----+-------------+---------+------------+--------+---------------+---------+---------+------------------------+------+----------+-------------+2 rows in set, 1 warning (0.00 sec) # 這個(gè)時(shí)候我們把population條件創(chuàng)建為一個(gè)輔助索引,驅(qū)動(dòng)表走的索引就是range。這也是最好的一種優(yōu)化了,沒有別的方式比這個(gè)性能更好了,知足吧!mysql> alter table city add index idx_p(population);mysql> desc select city.name,country.name from city left join country on city.countrycode=country.code where city.population<100;+----+-------------+---------+------------+--------+---------------+---------+---------+------------------------+------+----------+-----------------------+| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |+----+-------------+---------+------------+--------+---------------+---------+---------+------------------------+------+----------+-----------------------+| 1 | SIMPLE | city | NULL | range | idx_p | idx_p | 4 | NULL | 1 | 100.00 | Using index condition || 1 | SIMPLE | country | NULL | eq_ref | PRIMARY | PRIMARY | 3 | world.city.CountryCode | 1 | 100.00 | NULL |+----+-------------+---------+------------+--------+---------------+---------+---------+------------------------+------+----------+-----------------------+2 rows in set, 1 warning (0.00 sec)
  • const(system)

# 主鍵或唯一鍵等值查詢# 性能最好,只需回表一次,這是一種奢望!mysql> desc select * from city where id=1;+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+| 1 | SIMPLE | city | NULL | const | PRIMARY | PRIMARY | 4 | const | 1 | 100.00 | NULL |+----+-------------+-------+------------+-------+---------------+---------+---------+-------+------+----------+-------+1 row in set, 1 warning (0.00 sec)
  • NULL

# 查不到數(shù)據(jù)的時(shí)候性能最好!那我要你有何用!!!不用管了!!!mysql> desc select * from city where id=1000000000000000;

總結(jié)

通常最常見的執(zhí)行計(jì)劃類型是:range、ref、eq_ref。如果出現(xiàn)index或者all的情況,那就可能涉及到改寫sql查詢語句,或者得找業(yè)務(wù)溝通查詢條件了。

總結(jié)

以上是生活随笔為你收集整理的mysql 索引_MySQL之索引的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。