真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

怎么用好MySQL索引

本篇內(nèi)容主要講解“怎么用好MySQL索引”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“怎么用好MySQL索引”吧!

創(chuàng)新互聯(lián)公司是一家網(wǎng)站設(shè)計(jì)公司,集創(chuàng)意、互聯(lián)網(wǎng)應(yīng)用、軟件技術(shù)為一體的創(chuàng)意網(wǎng)站建設(shè)服務(wù)商,主營產(chǎn)品:響應(yīng)式網(wǎng)站開發(fā)成都品牌網(wǎng)站建設(shè)、成都營銷網(wǎng)站建設(shè)。我們專注企業(yè)品牌在網(wǎng)站中的整體樹立,網(wǎng)絡(luò)互動(dòng)的體驗(yàn),以及在手機(jī)等移動(dòng)端的優(yōu)質(zhì)呈現(xiàn)。成都網(wǎng)站設(shè)計(jì)、網(wǎng)站制作、移動(dòng)互聯(lián)產(chǎn)品、網(wǎng)絡(luò)運(yùn)營、VI設(shè)計(jì)、云產(chǎn)品.運(yùn)維為核心業(yè)務(wù)。為用戶提供一站式解決方案,我們深知市場的競爭激烈,認(rèn)真對待每位客戶,為客戶提供賞析悅目的作品,網(wǎng)站的價(jià)值服務(wù)。

怎么用好MySQL索引

為了更好地進(jìn)行解釋,我創(chuàng)建了一個(gè)存儲(chǔ)引擎為InnoDB的表user_innodb,并批量初始化了500W+條數(shù)據(jù)。包含主鍵id、姓名字段(name)、性別字段(gender,用0,1表示不同性別)、手機(jī)號(hào)字段(phone),并為name和phone字段創(chuàng)建了聯(lián)合索引。

CREATE TABLE `user_innodb` (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `gender` tinyint(1) DEFAULT NULL,
  `phone` varchar(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  INDEX IDX_NAME_PHONE (name, phone)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

1. 索引的代價(jià)

索引可以非常有效地提升查詢效率,既然這么好,我給每個(gè)字段都創(chuàng)建一個(gè)索引行不行?我勸你不要沖動(dòng)。

任何事情都有兩面,索引也不例外。過度使用索引,我們在空間和時(shí)間上都會(huì)付出相應(yīng)的代價(jià)。

1.1 空間上的代價(jià)

索引就是一棵B+數(shù),每創(chuàng)建一個(gè)索引都需要?jiǎng)?chuàng)建一棵B+樹,每一棵B+樹的節(jié)點(diǎn)都是一個(gè)數(shù)據(jù)頁,每一個(gè)數(shù)據(jù)頁默認(rèn)會(huì)占用16KB的磁盤空間,每一棵B+樹又會(huì)包含許許多多的數(shù)據(jù)頁。所以,大量創(chuàng)建索引,你的磁盤空間會(huì)被迅速消耗。

1.2 時(shí)間上的代價(jià)

空間上的代價(jià)你可以使用“鈔能力”來解決,但時(shí)間上的代價(jià)我們可能就束手無策了。

鏈表的維護(hù)

我以主鍵索引為例舉個(gè)例子,主鍵索引的B+樹的每一個(gè)節(jié)點(diǎn)內(nèi)的記錄都是按照主鍵值由小到大的順序,采用單向鏈表的方式進(jìn)行連接的。如下圖所示:

怎么用好MySQL索引

如果我現(xiàn)在要?jiǎng)h除主鍵id為1的記錄,會(huì)破壞3個(gè)數(shù)據(jù)頁內(nèi)的記錄排序,需要對這3個(gè)數(shù)據(jù)頁內(nèi)的記錄進(jìn)行重排列,插入和修改操作也是同理。

注:這里給大家提一嘴,其實(shí)刪除操作并不會(huì)立即進(jìn)行數(shù)據(jù)頁內(nèi)記錄的重排列,而是會(huì)給被刪除的記錄打上一個(gè)刪除的標(biāo)識(shí),等到合適的時(shí)候,再把記錄從鏈表中移除,但是總歸需要涉及到排序的維護(hù),勢必要消耗性能。

假如這張表有12個(gè)字段,我們?yōu)檫@張表的12個(gè)字段都設(shè)置了索引,我們刪除1條記錄,需要涉及到12棵B+樹的N個(gè)數(shù)據(jù)頁內(nèi)記錄的排序維護(hù)。

更糟糕的是,你增刪改記錄的時(shí)候,還可能會(huì)觸發(fā)數(shù)據(jù)頁的回收和分裂。還是以上圖為例,假如我刪除了id為13的記錄,那么數(shù)據(jù)頁124就沒有存在的必要了,會(huì)被InnoDB存儲(chǔ)引擎回收;我插入一條id為12的記錄,如果數(shù)據(jù)頁32的空間不足以存儲(chǔ)該記錄,InnoDB又需要進(jìn)行頁面分裂。我們不需要知道頁面回收和頁面分裂的細(xì)節(jié),但是能夠想象到這個(gè)操作會(huì)有多復(fù)雜。

如果每個(gè)字段都創(chuàng)建索引,所有這些索引的維護(hù)操作帶來的性能損耗,你能想象了吧。

查詢計(jì)劃

執(zhí)行查詢語句之前,MySQL查詢優(yōu)化器會(huì)基于cost成本對一條查詢語句進(jìn)行優(yōu)化,并生成一個(gè)執(zhí)行計(jì)劃。如果創(chuàng)建的索引太多,優(yōu)化器會(huì)計(jì)算每個(gè)索引的搜索成本,導(dǎo)致在分析過程中耗時(shí)太多,最終影響查詢語句的執(zhí)行效率。

2. 回表的代價(jià)

2.1 什么是回表

我再啰嗦一遍什么是回表,我們可以通過二級索引找到B+樹中的葉子結(jié)點(diǎn),但是二級索引的葉子節(jié)點(diǎn)的內(nèi)容并不全,只有索引列的值和主鍵值。我們需要拿著主鍵值再去聚簇索引(主鍵索引)的葉子節(jié)點(diǎn)中去拿到完整的用戶記錄,這個(gè)過程叫做回表。

怎么用好MySQL索引

上圖中我以name二級索引為例,并且只畫出了二級索引的葉子節(jié)點(diǎn)和聚簇索引的葉子節(jié)點(diǎn),省略了兩棵B+樹的非葉子節(jié)點(diǎn)。

從二級索引的葉子節(jié)點(diǎn)延伸出的3條線表示的就是回表操作。

2.2 回表的代價(jià)

我們根據(jù)name字段查找二級索引的葉子節(jié)點(diǎn)的代價(jià)還是比較小的,原因有二:

  • 葉子節(jié)點(diǎn)所在的頁通過雙向鏈表進(jìn)行關(guān)聯(lián),遍歷的速度比較快;
  • MySQL會(huì)盡量讓同一個(gè)索引的葉子節(jié)點(diǎn)的數(shù)據(jù)頁在磁盤空間中相鄰,盡力避免隨機(jī)IO。

但是二級索引葉子節(jié)點(diǎn)中的主鍵id的排布就沒有任何規(guī)律了,畢竟name索引是對name字段進(jìn)行排序的。進(jìn)行回表的時(shí)候,極有可能出現(xiàn)主鍵id所在的記錄在聚簇索引葉子節(jié)點(diǎn)中反復(fù)橫跳的情況(正如上圖中回表的3條線表示的那樣),也就是隨機(jī)IO。如果目標(biāo)數(shù)據(jù)頁恰好在內(nèi)存中的話效果倒也不會(huì)太差,但如果不在內(nèi)存中,還要從磁盤中加載一個(gè)數(shù)據(jù)頁的內(nèi)容(16KB)到內(nèi)存中,這個(gè)速度可就太慢了。

是不是說完了回表的代價(jià)之后,我會(huì)給出一種更高效的搜索方式?不是,回表已經(jīng)是一種比較高效的搜索方式了,我們需要做的就是盡量地減少回表操作帶來的損耗,總結(jié)起來就是兩點(diǎn):

  • 能不回表就不回;
  • 必須回表就減少回表的次數(shù)。

接下來先給大家介紹兩個(gè)與回表相關(guān)的重要概念,這兩個(gè)概念涉及到的方法也是索引使用原則的一部分,因?yàn)楸容^重要,在這里我把這兩個(gè)概念先解釋給大家聽。

3. 索引覆蓋、索引下推

3.1 索引覆蓋

想一下,如果非聚簇索引的葉子節(jié)點(diǎn)上有你想要的所有數(shù)據(jù),是不是就不需要回表了呢?比如我為name和phone字段創(chuàng)建了一個(gè)聯(lián)合索引,如下圖:

怎么用好MySQL索引

如果我們恰好只想搜索name、phone以及主鍵字段,

SELECT id, name,  phone FROM user_innodb WHERE name = "蟬沐風(fēng)";

可以直接從葉子節(jié)點(diǎn)獲取所有數(shù)據(jù),根本不需要回表操作。

我們把索引中已經(jīng)包含了所有需要讀取的列數(shù)據(jù)的查詢方式稱為覆蓋索引(或索引覆蓋)。

3.2 索引下推

3.2.1 概念

還是拿name和phone的聯(lián)合索引為例,我們要查詢所有name為「蟬沐風(fēng)」,并且手機(jī)尾號(hào)為6606的記錄,查詢SQL如下:

SELECT * FROM user_innodb WHERE name = "蟬沐風(fēng)" AND phone LIKE "%6606";

由于聯(lián)合索引的葉子節(jié)點(diǎn)的記錄是先按照name字段排序,name字段相同的情況下再按照phone字段排序,因此把%加在phone字段前面的時(shí)候,是無法利用索引的順序性來進(jìn)行快速比較的,也就是說這條查詢語句中只有name字段可以使用索引進(jìn)行快速比較和過濾。正常情況下查詢過程是這個(gè)樣子的:

  • InnoDB使用聯(lián)合索引查出所有name為蟬沐風(fēng)的二級索引數(shù)據(jù),得到3個(gè)主鍵值:3485,78921,423476;

  • 拿到主鍵索引進(jìn)行回表,到聚簇索引中拿到這三條完整的用戶記錄;

  • InnoDB把這3條完整的用戶記錄返回給MySQL的Server層,在Server層過濾出尾號(hào)為6606的用戶。

如下面兩幅圖所示,第一幅圖表示InnoDB通過3次回表拿到3條完整的用戶記錄,交給Server層;第二幅圖表示Server層經(jīng)過phone LIKE "%6606"條件的過濾之后找到符合搜索條件的記錄,返給客戶端。

怎么用好MySQL索引
存儲(chǔ)引擎把數(shù)據(jù)給Server層
怎么用好MySQL索引
Server層返回過濾數(shù)據(jù)

值得我們關(guān)注的是,索引的使用是在存儲(chǔ)引擎中進(jìn)行的,而數(shù)據(jù)記錄的比較是在Server層中進(jìn)行的?,F(xiàn)在我們把上述搜索考慮地極端一點(diǎn),假如數(shù)據(jù)表中10萬條記錄都符合name='蟬沐風(fēng)'的條件,而只有1條符合phone LIKE "%6606"條件,這就意味著,InnoDB需要將99999條無效的記錄傳輸給Server層讓其自己篩選,更嚴(yán)重的是,這99999條數(shù)據(jù)都是通過回表搜索出來的啊!關(guān)于回表的代價(jià)你已經(jīng)知道了。

現(xiàn)在引入索引下推。準(zhǔn)確來說,應(yīng)該叫做索引條件下推(Index Condition Pushdown,ICP),就是過濾的動(dòng)作由下層的存儲(chǔ)引擎層通過使用索引來完成,而不需要上推到Server層進(jìn)行處理。ICP是在MySQL5.6之后完善的功能。

再回顧一下,我們第一步已經(jīng)通過name = "蟬沐風(fēng)"在聯(lián)合索引的葉子節(jié)點(diǎn)中找到了符合條件的3條記錄,而且phone字段也恰好在聯(lián)合索引的葉子節(jié)點(diǎn)的記錄中。這個(gè)時(shí)候可以直接在聯(lián)合索引的葉子節(jié)點(diǎn)中進(jìn)行遍歷,篩選出尾號(hào)為6606的記錄,找到主鍵值為78921的記錄,最后只需要進(jìn)行1次回表操作即可找到符合全部條件的1條記錄,返回給Server層。

很明顯,使用ICP的方式能有效減少回表的次數(shù)。

另外,ICP是默認(rèn)開啟的,對于二級索引,只要能把條件甩給下面的存儲(chǔ)引擎,存儲(chǔ)引擎就會(huì)進(jìn)行過濾,不需要我們干預(yù)。

3.2.2 演示

查看一下當(dāng)前ICP的狀態(tài):

SHOW VARIABLES LIKE 'optimizer_switch';

怎么用好MySQL索引

執(zhí)行以下SQL語句,并用EXPLAIN查看一下執(zhí)行計(jì)劃,此時(shí)的執(zhí)行計(jì)劃是Using index condition

EXPLAIN SELECT * FROM user_innodb WHERE name = "蟬沐風(fēng)" AND phone LIKE "%6606";

怎么用好MySQL索引

然后關(guān)閉ICP

SET optimizer_switch="index_condition_pushdown=off";

再查看一下ICP的狀態(tài)

怎么用好MySQL索引

再次執(zhí)行查詢語句,并用EXPLAIN查看一下執(zhí)行計(jì)劃,此時(shí)的執(zhí)行計(jì)劃是Using where

EXPLAIN SELECT * FROM user_innodb WHERE name = "蟬沐風(fēng)" AND phone LIKE "%6606";

怎么用好MySQL索引

注:即使?jié)M足索引下推的使用條件,查詢優(yōu)化器也未必會(huì)使用索引下推,因?yàn)榭赡艽嬖诟咝У姆绞健?/p>

由于之前我給name字段創(chuàng)建了索引,導(dǎo)致一直沒有使用索引下推,EXPLAIN語句顯示使用了name索引,而不是name和phone的聯(lián)合索引;刪除name索引之后,才獲得上述截圖的效果。大家做實(shí)驗(yàn)的時(shí)候需要注意。


到目前為止大家應(yīng)該清楚了索引和回表帶來的性能問題,講這些自然不是為了恐嚇大家讓大家遠(yuǎn)離索引,相反,我們要以正確的方式積極擁抱索引,最大限度降低其帶來的負(fù)面影響,放大其優(yōu)勢。如何用好索引,從兩個(gè)方面考慮:

  • 高效發(fā)揮已經(jīng)創(chuàng)建的索引的作用(避免索引失效)
  • 為合適的列創(chuàng)建合適的索引(索引創(chuàng)建原則)

4. 什么時(shí)候索引會(huì)失效?

4.1 違反最左前綴原則

拿我們文章開始創(chuàng)建的聯(lián)合索引為例,該聯(lián)合索引的B+樹數(shù)據(jù)頁內(nèi)的記錄首先按照name字段進(jìn)行排序,name字段相同的情況下,再按照phone字段進(jìn)行排序。

所以,如果我們直接使用phone字段進(jìn)行搜索,無法利用索引的順序性。

EXPLAIN SELECT * FROM user_innodb WHERE phone = "13203398311";

怎么用好MySQL索引

EXPLAIN可以查看搜索語句的執(zhí)行計(jì)劃,其中,possible_keys列表示在當(dāng)前查詢中,可能用到的索引有哪一些;key列表示實(shí)際用到的索引有哪一些。

但是一旦加上name的搜索條件,就會(huì)使用到聯(lián)合索引,而且不需要在意name在WHERE子句中的位置,因?yàn)椴樵儍?yōu)化器會(huì)幫我們優(yōu)化。

EXPLAIN SELECT * FROM user_innodb WHERE phone = "13203398311" AND name = '蟬沐風(fēng)';

怎么用好MySQL索引

4.2 使用反向查詢(!=, <>,NOT LIKE)

MySQL在使用反向查詢(!=, <>, NOT LIKE)的時(shí)候無法使用索引,會(huì)導(dǎo)致全表掃描,覆蓋索引除外。

EXPLAIN SELECT * FROM user_innodb WHERE name != '蟬沐風(fēng)';

怎么用好MySQL索引

4.3 LIKE以通配符開頭

當(dāng)使用name LIKE '%沐風(fēng)'或者name LIKE '%沐%'這兩種方式都會(huì)使索引失效,因?yàn)槁?lián)合索引的B+樹數(shù)據(jù)頁內(nèi)的記錄首先按照name字段進(jìn)行排序,這兩種搜索方式不在意name字段的開頭是什么,自然就無法使用索引,只能通過全表掃描的方式進(jìn)行查詢。

EXPLAIN SELECT * FROM user_innodb WHERE name LIKE '%沐風(fēng)';

怎么用好MySQL索引

但是使用通配符結(jié)尾就沒有問題

EXPLAIN SELECT * FROM user_innodb WHERE name LIKE '蟬沐%';

怎么用好MySQL索引

4.4 對索引列做任何操作

如果不是單純使用索引列,而是對索引列做了其他操作,例如數(shù)值計(jì)算、使用函數(shù)、(手動(dòng)或自動(dòng))類型轉(zhuǎn)換等操作,會(huì)導(dǎo)致索引失效。

4.4.1 使用函數(shù)
EXPLAIN SELECT * FROM user_innodb WHERE LEFT(name,3) = '蟬沐風(fēng)';

怎么用好MySQL索引

MySQL8.0新增了函數(shù)索引的功能,我們可以給函數(shù)作用之后的結(jié)果創(chuàng)建索引,使用以下語句

ALTER TABLE user_innodb ADD KEY IDX_NAME_LEFT ((left(name,3)));

再次執(zhí)行EXPLAIN語句,此時(shí)索引生效

怎么用好MySQL索引

4.4.2 使用表達(dá)式
EXPLAIN SELECT * FROM user_innodb WHERE id + 1 = 1100000;

怎么用好MySQL索引

換一種方式,單獨(dú)使用id,就能高效使用索引:

EXPLAIN SELECT * FROM user_innodb WHERE id = 1100000 - 1;

怎么用好MySQL索引

4.4.3 使用類型轉(zhuǎn)換

例1

user_innodb中的phone字段為varchar類型,實(shí)驗(yàn)之前我們先給phone字段創(chuàng)建個(gè)索引

ALTER TABLE user_innodb ADD INDEX IDX_PHONE (phone);

隨便搜索一個(gè)存在的手機(jī)號(hào),看一下索引是否成功

EXPLAIN SELECT * FROM user_innodb WHERE phone = '13203398311';

怎么用好MySQL索引

可以看到能使用到索引,現(xiàn)在我們稍微修改一下,把phone = '13203398311'修改為phone = 13203398311,這意味著我們將字符串的搜索條件改成了整形的搜索條件,再看一下還會(huì)不會(huì)使用到索引:

EXPLAIN SELECT * FROM user_innodb WHERE phone = 13203398311;

怎么用好MySQL索引

顯示索引失效。

例2

我們再看一個(gè)例子,主鍵id類型是bigint,但是在搜索條件中我估計(jì)使用字符串類型:

EXPLAIN SELECT * FROM user_innodb WHERE id = '1099999';

怎么用好MySQL索引

總結(jié)

稍微總結(jié)一下這個(gè)問題,當(dāng)索引字段類型為字符串時(shí),使用數(shù)字類型進(jìn)行搜索不會(huì)用到索引;而索引字段類型為數(shù)字類型時(shí),使用字符串類型進(jìn)行搜索會(huì)使用到索引。

要搞明白這個(gè)問題,我們需要知道MySQL的數(shù)據(jù)類型轉(zhuǎn)換規(guī)則是什么。簡單地說就是MySQL會(huì)自動(dòng)將數(shù)字轉(zhuǎn)化為字符串,還是將字符串轉(zhuǎn)化為數(shù)字。

一個(gè)簡單的方法是,通過SELECT '10' > 9的結(jié)果來確定MySQL的類型轉(zhuǎn)換規(guī)則:

  • 結(jié)果為1,說明MySQL會(huì)自動(dòng)將字符串類型轉(zhuǎn)化為數(shù)字,相當(dāng)于執(zhí)行了SELECT 10 > 9;
  • 結(jié)果為0,說明MySQL會(huì)自動(dòng)將數(shù)字轉(zhuǎn)化為字符串,相當(dāng)于執(zhí)行了SELECT '10' > '9'。
mysql> SELECT '10' > 9;
+----------+
| '10' > 9 |
+----------+
|        1 |
+----------+
1 row in set (0.00 sec)

上面的執(zhí)行結(jié)果為1,說明MySQL遇到類型轉(zhuǎn)換時(shí),會(huì)自動(dòng)將字符串轉(zhuǎn)換為數(shù)字類型,因此對于例1:

EXPLAIN SELECT * FROM user_innodb WHERE phone = 13203398311;

就相當(dāng)于

EXPLAIN SELECT * FROM user_innodb WHERE CAST(phone AS signed int) = 13203398311;

也就是對索引字段使用了函數(shù),按照前文的介紹,對索引使用函數(shù)是不會(huì)使用到索引的。

對于例2:

EXPLAIN SELECT * FROM user_innodb WHERE id = '1099999';

就相當(dāng)于

EXPLAIN SELECT * FROM user_innodb WHERE id = CAST('1099999' AS unsigned int);

沒有在索引字段添加任何操作,因此能夠使用到索引。

4.5 OR連接

使用OR連接的查詢語句,如果OR之前的條件列是索引列,但是OR之后的條件列不是索引列,則不會(huì)使用索引。舉例:

EXPLAIN SELECT * FROM user_innodb WHERE id = 1099999 OR gender = 0;

怎么用好MySQL索引


上面總結(jié)了一些索引失效的場景,這些經(jīng)驗(yàn)的總結(jié)往往對SQL的優(yōu)化很有益處,但同時(shí)需要注意的是這些經(jīng)驗(yàn)并非金科玉律。

比如使用<>查詢時(shí),在某些時(shí)候是可以用到索引的:

EXPLAIN SELECT * FROM user_innodb WHERE id <> 1099999;

怎么用好MySQL索引

最終是否使用索引,完全取決于MySQL的優(yōu)化器,而優(yōu)化器的判定依據(jù)就是cost開銷(Cost Base Optimizer),優(yōu)化器并非基于具體的規(guī)則,也不是基于語義,就是單純地執(zhí)行開銷小的方案罷了。所以在·EXPLAIN·的結(jié)果中你會(huì)看到possible_keys一列,優(yōu)化器會(huì)把這里邊的索引都試一遍(是不是又加深了對不能隨便創(chuàng)建索引的認(rèn)識(shí)呢?),然后選一個(gè)開銷最小的,如果都不太行,那就直接全表掃描好了。

而cost開銷,和數(shù)據(jù)庫版本、數(shù)據(jù)量等都有關(guān)系,因此如果想更精準(zhǔn)地提升索引功能性,擁抱EXPLAIN吧!

5. 索引創(chuàng)建(使用)原則

之前講過的索引覆蓋和索引下推都可以作為索引創(chuàng)建的原則,就是在創(chuàng)建索引的時(shí)候,盡量發(fā)揮索引覆蓋和索引下推的優(yōu)勢。

盡量避免上述提及到的索引可能失效的情況的出現(xiàn),同樣是索引的使用原則。

除此之外,再給大家介紹一些。

5.1 不為離散度低的列創(chuàng)建索引

先來看一下列的離散度公式:COUNT(DISTINCT(column_name)) / COUNT(*),列的不重復(fù)值的個(gè)數(shù)與所有數(shù)據(jù)行的比例。簡而言之,如果列的重復(fù)值越多,列的離散度越低。重復(fù)值越少,離散度就越高。

舉個(gè)例子,gender(性別)列只有0、1兩個(gè)值,列的離散度非常低,假如我們?yōu)樵摿袆?chuàng)建索引,我們會(huì)在二級索引中搜索到大量的重復(fù)數(shù)據(jù),然后進(jìn)行大量回表操作。大量回表哈?你懂了吧。

不要為重復(fù)值多的列創(chuàng)建索引

5.2 只為用于搜索、排序或分組的列創(chuàng)建索引

我們只為出現(xiàn)在WHERE子句中的列或者出現(xiàn)在ORDER BY和GROUP BY子句中的列創(chuàng)建索引即可。僅出現(xiàn)在查詢列表中的列不需要?jiǎng)?chuàng)建索引。

5.3 用好聯(lián)合索引

用2條SQL語句來說明這個(gè)問題:

1. SELECT * FROM user_innodb WHERE name = '蟬沐風(fēng)' AND phone = '13203398311';
2. SELECT * FROM user_innodb WHERE name = '蟬沐風(fēng)';

語句1和語句2都能夠使用索引,這帶給我們的一個(gè)索引設(shè)計(jì)原則就是:

不要為聯(lián)合索引的第一個(gè)索引列單獨(dú)創(chuàng)建索引

因?yàn)槁?lián)合索引本身就是先按照name列進(jìn)行排序,因此聯(lián)合索引對name的搜索是有效的,不需要單獨(dú)為name再創(chuàng)建索引了。也正因?yàn)榇?/p>

建立聯(lián)合索引的時(shí)候,一定要把最常用的列放在最左邊

5.4 對過長的字段,建立前綴索引

如果一個(gè)字符串格式的列占用的空間比較大(就是說允許存儲(chǔ)比較長的字符串?dāng)?shù)據(jù)),為該列創(chuàng)建索引,就意味著該列的數(shù)據(jù)會(huì)被完整地記錄在每個(gè)數(shù)據(jù)頁的每條記錄中,會(huì)占用相當(dāng)大的存儲(chǔ)空間。

對此,我們可以為該列的前幾個(gè)字符創(chuàng)建索引,也就是在二級索引的記錄中只會(huì)保留字符串的前幾個(gè)字符。比如我們可以為phone列創(chuàng)建索引,索引只保留手機(jī)號(hào)的前3位:

ALTER TABLE user_innodb ADD INDEX IDX_PHONE_3 (phone(3));

然后執(zhí)行下面的SQL語句:

EXPLAIN SELECT * FROM user_innodb WHERE phone = '1320';

怎么用好MySQL索引

由于在IDX_PHONE_3索引中只保留了手機(jī)號(hào)的前3位數(shù)字,所以我們只能定位到以132開頭的二級索引記錄,然后在遍歷所有的這些二級索引記錄時(shí)再判斷它們是否滿足第4位數(shù)為0的條件。

當(dāng)列中存儲(chǔ)的字符串包含的字符較多時(shí),為該字段建立前綴索引可以有效節(jié)省磁盤空間

5.5 頻繁更新的值,不要作為主鍵或索引

因?yàn)榭赡苌婕暗綌?shù)據(jù)頁分裂的情況,會(huì)影響性能。

5.6 隨機(jī)無序的值,不建議作為索引,例如身份證、UUID

到此,相信大家對“怎么用好MySQL索引”有了更深的了解,不妨來實(shí)際操作一番吧!這里是創(chuàng)新互聯(lián)網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!


新聞名稱:怎么用好MySQL索引
網(wǎng)頁路徑:http://weahome.cn/article/ijhiph.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部