(十二)MySQL中的索引


1重绷、概述

??索引是一種特殊的文件(InnoDB數(shù)據(jù)表上的索引是表空間的一個(gè)組成部分),它們包含著對(duì)數(shù)據(jù)表里所有記錄的引用指針膜毁≌炎浚可以將索引理解為一本書(shū)前面的目錄,能加快數(shù)據(jù)的查詢速度瘟滨。
  對(duì)于沒(méi)有索引的表候醒,MySQL會(huì)遍歷全部數(shù)據(jù)后選擇符合條件的記錄,因此單表查詢可能幾十萬(wàn)數(shù)據(jù)就是瓶頸杂瘸,而通常大型網(wǎng)站單日就可能會(huì)產(chǎn)生幾十萬(wàn)甚至幾百萬(wàn)的數(shù)據(jù)倒淫,沒(méi)有索引查詢會(huì)變的非常緩慢,而有了相應(yīng)的索引之后败玉,MySQL會(huì)直接在索引中查找符合條件的選項(xiàng)敌土,效率會(huì)大大提升镜硕。

??索引分為聚簇索引和非聚簇索引兩種:

  1. 聚簇索引是按照數(shù)據(jù)存放的物理位置為順序的,對(duì)于數(shù)據(jù)而言返干,通常來(lái)說(shuō)物理順序結(jié)構(gòu)只有一種兴枯,因此每張數(shù)據(jù)表也只能有一個(gè)聚簇索引。在設(shè)置主鍵時(shí)矩欠,系統(tǒng)會(huì)默認(rèn)為其加上聚簇索引财剖,當(dāng)然也可以使用其他字段作為索引,此時(shí)需要在設(shè)置主鍵之前先手動(dòng)為待選字段添加上唯一的聚簇索引癌淮,然后再設(shè)置主鍵躺坟,就可以解決這一問(wèn)題。
  • 非聚簇索引記錄的物理順序與邏輯順序沒(méi)有必然的聯(lián)系乳蓄,與數(shù)據(jù)的存儲(chǔ)物理位置也沒(méi)有關(guān)系咪橙;每張數(shù)據(jù)表對(duì)應(yīng)的非聚簇索引可以有多個(gè),根據(jù)不同列的約束可以建立不同要求的非聚簇索引栓袖。

??簡(jiǎn)單總結(jié)即匣摘,聚簇索引能提高多行檢索的效率,而非聚簇索引對(duì)于單行的檢索更有效裹刮。


2音榜、索引的類型

普通索引

??普通索引是最基本的索引,它沒(méi)有任何限制捧弃,是大多數(shù)情況下用到的索引赠叼。

直接創(chuàng)建索引
CREATE INDEX index_name ON tbl_name(col_name(length));
修改數(shù)據(jù)表結(jié)構(gòu)時(shí)添加索引
ALTER TABLE tbl_name ADD INDEX index_name (col_name(length));
創(chuàng)建數(shù)據(jù)表時(shí)同時(shí)創(chuàng)建索引
CREATE TABLE tbl_name (
……
INDEX index_name (col_name(length))
)

唯一索引

??唯一索引與普通索引類似,不同之處是:索引列的值必須唯一违霞,但允許有空值(注意和主鍵不同)嘴办。如果是組合索引,則列值的組合必須唯一买鸽,創(chuàng)建方法和普通索引類似涧郊。

直接創(chuàng)建索引
CREATE UNIQUE INDEX index_name ON tbl_name(col_name(length));
修改數(shù)據(jù)表結(jié)構(gòu)時(shí)添加索引
ALTER TABLE tbl_name ADD UNIQUE index_name (col_name(length));
創(chuàng)建數(shù)據(jù)表時(shí)同時(shí)創(chuàng)建索引
CREATE TABLE tbl_name (
……
UNIQUE index_name (col_name(length))
)

全文索引

??全文索引僅可用于MyISAM數(shù)據(jù)表,對(duì)于較大的數(shù)據(jù)集而言眼五,將資料輸入進(jìn)一個(gè)沒(méi)有全文索引的數(shù)據(jù)表中妆艘,然后創(chuàng)建索引;其速度遠(yuǎn)比把資料輸入現(xiàn)有全文索引的數(shù)據(jù)表中更快看幼。不過(guò)對(duì)于大容量的數(shù)據(jù)表來(lái)說(shuō)批旺,生成全文索引是一個(gè)非常消耗時(shí)間及硬盤(pán)空間的做法。

直接創(chuàng)建索引
CREATE FULLTEXT INDEX index_name ON tbl_name(col_name(length));
修改數(shù)據(jù)表結(jié)構(gòu)時(shí)添加索引
ALTER TABLE tbl_name ADD FULLTEXT index_name (col_name(length));
創(chuàng)建數(shù)據(jù)表時(shí)同時(shí)創(chuàng)建索引
CREATE TABLE tbl_name (
……
FULLTEXT index_name (col_name(length))
)

多列索引诵姜、單列索引

??單個(gè)多列索引與多個(gè)單列索引的查詢效果不同汽煮。當(dāng)使用多個(gè)單列索引并執(zhí)行查詢時(shí),MySQL只會(huì)從多個(gè)索引中選擇一個(gè)限制最為嚴(yán)格的索引,剩余的索引將起不到作用暇赤。在建立多列索引時(shí)心例,字段的順序也是需要注意的,應(yīng)該將嚴(yán)格的索引放在前面翎卓,這樣篩選的力度會(huì)更大契邀,效率更高。


組合索引(最左前綴)

??平時(shí)用的SQL查詢語(yǔ)句一般都有比較多的限制條件失暴,因此為了進(jìn)一步提高M(jìn)ySQL的效率坯门,就要考慮建立組合索引。例如上圖中針對(duì)“l(fā)ast_name”和“first_name”建立一個(gè)組合索引:

INDEX name (last_name,first_name)

??建立這樣的組合索引逗扒,其實(shí)是相當(dāng)于分別建立了下面兩組組合索引:

(last_name,first_name)
(last_name)

??之所以沒(méi)有(first_name)這樣的組合索引古戴,是因?yàn)镸ySQL組合索引采取“最左前綴”的結(jié)果。簡(jiǎn)單的理解就是只從最左面的開(kāi)始組合矩肩,組合索引的最左列一定選擇好现恼,否則無(wú)法起到索引的效果。如果查詢時(shí)最左列不在查詢條件中則該組合索引不會(huì)被使用黍檩。
??最左列一定是使用最頻繁的列叉袍,然而并不是只要包含在組合索引中的列的查詢都會(huì)用到該組合索引,例如以下形式的查詢語(yǔ)句能夠使用組合索引:

SELECT * FROM tbl_name WHERE last_name='Widenius';  
  
SELECT * FROM tbl_name WHERE last_name='Widenius' AND first_name='Michael';  
  
SELECT * FROM tbl_name WHERE last_name='Widenius' AND (first_name='Michael' OR first_name='Monty');  
  

??以下形式的查詢語(yǔ)句不能使用組合索引:

SELECT * FROM tbl_name WHERE first_name='Michael';  
  
SELECT * FROM tbl_name WHERE last_name='Widenius' OR first_name='Michael';  

查看索引

SHOW INDEX FROM tbl_name;
SHOW KEYS FROM tbl_name;

刪除索引

DORP INDEX index_name ON tbl_name;
ALTER TABLE tbl_name DROP INDEX index_name;


3刽酱、索引的缺點(diǎn)

??雖然索引極大提高了數(shù)據(jù)查詢的速度喳逛,但同時(shí)卻會(huì)降低更新表的速度,如對(duì)表進(jìn)行INSERT棵里、UPDATE和DELET時(shí)润文,MySQL不僅要保存數(shù)據(jù),還要保存一下索引文件殿怜,這樣就會(huì)降低數(shù)據(jù)的維護(hù)速度典蝌。
  建立索引會(huì)占用磁盤(pán)空間,一般而言這個(gè)問(wèn)題不太嚴(yán)重头谜,但如果在一個(gè)擁有大量數(shù)據(jù)的表上創(chuàng)建了多種組合索引骏掀,索引文件的會(huì)膨脹很快。
  索引只是提高效率的一個(gè)因素柱告,如果有大數(shù)據(jù)量的表砖织,就需要花費(fèi)時(shí)間研究建立最優(yōu)秀的索引組合,或優(yōu)化查詢語(yǔ)句末荐,且隨著數(shù)據(jù)量的增加,維護(hù)索引的成本也會(huì)增加新锈。


4甲脏、使用索引的注意事項(xiàng)

如何選擇聚簇索引或非聚簇索引

動(dòng)作描述 使用聚簇索引 使用非聚簇索引
列經(jīng)常被分組排序 使用 使用
返回某范圍內(nèi)的數(shù)據(jù) 使用 不使用
一個(gè)或極少不同值 不使用 不使用
少量的不同值 使用 不使用
大量的不同值 不使用 使用
頻繁更新的列 不使用 使用
外鍵列 使用 使用
主鍵列 使用 使用
頻繁修改索引列 不使用 使用

使用前綴長(zhǎng)度

??對(duì)于CHAR和VARCHAR列,只用一列的一部分就可創(chuàng)建索引。創(chuàng)建索引時(shí)块请,使用col_name(length)語(yǔ)法娜氏,對(duì)前綴編制索引。前綴包括每列值的前l(fā)ength個(gè)字符墩新。BLOB和TEXT列也可以編制索引贸弥,但是必須給出前綴長(zhǎng)度。
  例如海渊,有一個(gè)CHAR(255)的列绵疲,如果在前10個(gè)或20個(gè)字符內(nèi),多數(shù)值是唯一的臣疑,那么就不要對(duì)整個(gè)列進(jìn)行索引盔憨,而是CREATE INDEX index_name ON tbl_name(col_name(10))。
  使用短索引不僅可以提高查詢速度讯沈,而且可以節(jié)省磁盤(pán)空間和I/O操作郁岩。

LIKE語(yǔ)句

??若LIKE語(yǔ)句是不以通配符開(kāi)頭的常量串,MySQL會(huì)使用索引缺狠。比如:

SELECT * FROM tbl_name WHERE key_col LIKE 'Patrick%'
或
SELECT * FROM tbl_name WHERE key_col LIKE 'Pat%_ck%'

??而以下情況無(wú)法使用索引:

//LIKE語(yǔ)句以通配符開(kāi)頭
SELECT * FROM tbl_name WHERE key_col LIKE '%Patrick%'
//LIKE語(yǔ)句不是常量串
SELECT * FROM tbl_name WHERE key_col LIKE other_col

WHERE子句

  1. 在WHERE子句的查詢條件中進(jìn)行運(yùn)算會(huì)導(dǎo)致索引失效问慎;
  2. 在WHERE子句的查詢條件中使用了函數(shù)會(huì)導(dǎo)致索引失效;
  3. 在WHERE子句的查詢條件中使用“or”來(lái)連接條件會(huì)導(dǎo)致索引失效挤茄;
  4. 在WHERE子句的查詢條件中使用“!=”或“<>”操作符會(huì)導(dǎo)致索引失效如叼。

多表連接

??如果數(shù)據(jù)表需要很多連接查詢,首先應(yīng)該確認(rèn)兩張數(shù)據(jù)表中連接的字段已經(jīng)創(chuàng)建索引驮樊。這樣薇正,MySQL內(nèi)部會(huì)啟動(dòng)優(yōu)化連接的SQL語(yǔ)句的機(jī)制。
  除此之外囚衔,這些被用來(lái)連接的字段挖腰,應(yīng)該是屬于同一類型。例如练湿,如果要把DECIMAL類型的字段和一個(gè)INT類型的字段連接在一起猴仑,MySQL就無(wú)法使用它們的索引。另外對(duì)于STRING類型肥哎,還需要有相同的字符集才行(兩張數(shù)據(jù)表的字符集有可能不一樣)辽俗。

避免使用“SELECT * ”

??從數(shù)據(jù)庫(kù)里讀出的數(shù)據(jù)越多,那么查詢就會(huì)變得越慢篡诽。而且如果數(shù)據(jù)庫(kù)服務(wù)器和WEB服務(wù)器是兩臺(tái)獨(dú)立的服務(wù)器的話崖飘,還會(huì)增加網(wǎng)絡(luò)傳輸?shù)呢?fù)擔(dān)。因此杈女,應(yīng)該養(yǎng)成需要什么就查找什么的好習(xí)慣:

//不推薦使用
SELECT * FROM tbl_name WHERE id = 1;
//推薦使用
SELECT username FROM tbl_name WHERE id = 1;

為每張數(shù)據(jù)表設(shè)置一個(gè)ID字段

??應(yīng)該為數(shù)據(jù)庫(kù)里的每張表都設(shè)置一個(gè)ID做為其主鍵朱浴,且最好為INT類型的(推薦使用UNSIGNED)吊圾,并設(shè)置上AUTO_INCREMENT。
  使用例如VARCHAR類型來(lái)當(dāng)主鍵會(huì)使MySQL性能下降翰蠢。而且项乒,還有一些操作,例如集群梁沧、分區(qū)等需要使用主鍵檀何,在這些情況下,主鍵的性能和設(shè)置變得非常重要廷支。

盡可能的使用“NOT NULL”

??要盡可能地把字段定義為“NOT NULL”频鉴。即使該數(shù)據(jù)表無(wú)須保存“NULL”(沒(méi)有值),也有許多表包含了可空列(Nullable Column)酥泞,這僅僅因?yàn)樗悄J(rèn)選項(xiàng)砚殿。除非真的要保存“NULL”,否則就把字段定義為“NOT NULL”芝囤。
  MySQL難以優(yōu)化引用了可空列的查詢似炎,它會(huì)使索引、索引統(tǒng)計(jì)和值更加復(fù)雜悯姊∠勖辏可空列需要更多的儲(chǔ)存空間,還需要在MySQL內(nèi)部進(jìn)行特殊處理悯许。當(dāng)可空列被索引的時(shí)候仆嗦,每條記錄都需要一個(gè)額外的字節(jié),還可能導(dǎo)致MyISAM中固定大小的索引(例如一個(gè)整數(shù)字段上的索引)變成可變大小的索引先壕。
  即使要在表中儲(chǔ)存“沒(méi)有值”的字段瘩扼,還是有可能不使用“NULL”的±牛考慮使用0集绰、特殊值或空字符串來(lái)代替它。


5谆棺、索引的SQL語(yǔ)句匯總

  • 普通索引
    直接創(chuàng)建索引
    CREATE INDEX index_name ON tbl_name(col_name(length));
    修改數(shù)據(jù)表結(jié)構(gòu)時(shí)添加索引
    ALTER TABLE tbl_name ADD INDEX index_name (col_name(length));
    創(chuàng)建數(shù)據(jù)表時(shí)同時(shí)創(chuàng)建索引
    CREATE TABLE tbl_name (
    ……
    INDEX index_name (col_name(length))
    )

  • 唯一索引
    直接創(chuàng)建索引
    CREATE UNIQUE INDEX index_name ON tbl_name(col_name(length));
    修改數(shù)據(jù)表結(jié)構(gòu)時(shí)添加索引
    ALTER TABLE tbl_name ADD UNIQUE index_name (col_name(length));
    創(chuàng)建數(shù)據(jù)表時(shí)同時(shí)創(chuàng)建索引
    CREATE TABLE tbl_name (
    ……
    UNIQUE index_name (col_name(length))
    )

  • 全文索引
    直接創(chuàng)建索引
    CREATE FULLTEXT INDEX index_name ON tbl_name(col_name(length));
    修改數(shù)據(jù)表結(jié)構(gòu)時(shí)添加索引
    ALTER TABLE tbl_name ADD FULLTEXT index_name (col_name(length));
    創(chuàng)建數(shù)據(jù)表時(shí)同時(shí)創(chuàng)建索引
    CREATE TABLE tbl_name (
    ……
    FULLTEXT index_name (col_name(length))
    )

  • 查看索引
    SHOW INDEX FROM tbl_name;
    SHOW KEYS FROM tbl_name;

  • 刪除索引
    DORP INDEX index_name ON tbl_name;
    ALTER TABLE tbl_name DROP INDEX index_name;


版權(quán)聲明:歡迎轉(zhuǎn)載栽燕,歡迎擴(kuò)散,但轉(zhuǎn)載時(shí)請(qǐng)標(biāo)明作者以及原文出處改淑,謝謝合作碍岔!             ↓↓↓
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市朵夏,隨后出現(xiàn)的幾起案子蔼啦,更是在濱河造成了極大的恐慌,老刑警劉巖仰猖,帶你破解...
    沈念sama閱讀 206,602評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件捏肢,死亡現(xiàn)場(chǎng)離奇詭異掠河,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)猛计,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)爆捞,“玉大人奉瘤,你說(shuō)我怎么就攤上這事≈笊” “怎么了盗温?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,878評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)成肘。 經(jīng)常有香客問(wèn)我卖局,道長(zhǎng),這世上最難降的妖魔是什么双霍? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,306評(píng)論 1 279
  • 正文 為了忘掉前任砚偶,我火速辦了婚禮,結(jié)果婚禮上洒闸,老公的妹妹穿的比我還像新娘染坯。我一直安慰自己,他們只是感情好丘逸,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評(píng)論 5 373
  • 文/花漫 我一把揭開(kāi)白布单鹿。 她就那樣靜靜地躺著,像睡著了一般深纲。 火紅的嫁衣襯著肌膚如雪仲锄。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,071評(píng)論 1 285
  • 那天湃鹊,我揣著相機(jī)與錄音儒喊,去河邊找鬼。 笑死涛舍,一個(gè)胖子當(dāng)著我的面吹牛澄惊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播富雅,決...
    沈念sama閱讀 38,382評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼掸驱,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了没佑?” 一聲冷哼從身側(cè)響起毕贼,我...
    開(kāi)封第一講書(shū)人閱讀 37,006評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蛤奢,沒(méi)想到半個(gè)月后鬼癣,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體陶贼,經(jīng)...
    沈念sama閱讀 43,512評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評(píng)論 2 325
  • 正文 我和宋清朗相戀三年待秃,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了拜秧。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,094評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡章郁,死狀恐怖枉氮,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情暖庄,我是刑警寧澤聊替,帶...
    沈念sama閱讀 33,732評(píng)論 4 323
  • 正文 年R本政府宣布培廓,位于F島的核電站惹悄,受9級(jí)特大地震影響肩钠,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蔬将,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評(píng)論 3 307
  • 文/蒙蒙 一爷速、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧霞怀,春花似錦、人聲如沸毙石。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,286評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)滞时。三九已至,卻和暖如春滤灯,著一層夾襖步出監(jiān)牢的瞬間坪稽,已是汗流浹背鳞骤。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,512評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留豫尽,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,536評(píng)論 2 354
  • 正文 我出身青樓美旧,卻偏偏與公主長(zhǎng)得像贬墩,于是被迫代替她去往敵國(guó)和親妄呕。 傳聞我的和親對(duì)象是個(gè)殘疾皇子陶舞,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容