數據庫使用2--索引系列

咱們首先討論索引,由於它是加快查詢的最重要的工具。還有其餘加快查詢的技術,可是最有效的莫過於恰當地使用索引了。
在 MySQL 的郵件清單上,人們一般詢問關於使查詢更快的問題。在大量的案例中,都是由於表上沒有索引,通常只要加上索引就能夠當即解決問題。但這樣也並不是老是有效,由於優化並不是老是那樣簡單。
然而,若是不使用索引,在許多情形下,用其餘手段改善性能只會是浪費時間。應該首先考慮使用索引取得最大的性能改善,而後再尋求其餘可能有幫助的技術。
本節介紹索引是什麼、它怎樣改善查詢性能、索引在什麼狀況下可能會下降性能,以及怎樣爲表選擇索引。
下一節,咱們將討論 MySQL 的查詢優化程序。
除了知道怎樣建立索引外,瞭解一些優化程序的知識也是有好處的,由於這樣能夠更好地利用所建立的索引。某些編寫查詢的方法實際上會妨礙索引的效果,應該避免這種狀況出現。
(雖然並不是總會這樣。有時也會但願忽略優化程序的做用。咱們也將介紹這些狀況。)
索引對單個表查詢的影響
索引被用來快速找出在一個列上用一特定值的行。沒有索引,MySQL不得不首先以第一條記錄開始並而後讀完整個表直到它找出相關的行。表越大,花費時間越多。
若是表對於查詢的列有一個索引,MySQL能快速到達一個位置去搜尋到數據文件的中間,沒有必要考慮全部數據。若是一個表有1000 行,這比順序讀取至少快100倍。注意你須要存取幾乎全部1000行,它較快的順序讀取,由於此時咱們避免磁盤尋道。
例如對下面這樣的一個student表:mysql

mysql>SELECT * FROM student
+——+———+———+———+———+
| id   | name    | english | chinese | history |
+——+———+———+———+———+
|   12 | Tom     |      66 |      93 |      67 |
|   56 | Paul    |      78 |      52 |      75 |
|   10 | Marry   |      54 |      89 |      74 |
|    4 | Tina    |      99 |      83 |      48 |
|   39 | William |      43 |      96 |      52 |
|   74 | Stone   |      42 |      40 |      61 |
|   86 | Smith   |      49 |      85 |      78 |
|   37 | Black   |      49 |      63 |      47 |
|   89 | White   |      94 |      31 |      52 |
+——+———+———+———+———+

這樣,咱們試圖對它進行一個特定查詢時,就不得不作一個全表的掃描,速度很慢。
例如,咱們查找出全部english成績不及格的學生:算法

mysql>SELECT name,english FROM student WHERE english<60;
+———+———+
| name    | english |
+———+———+
| Marry   |      54 |
| William |      43 |
| Stone   |      42 |
| Smith   |      49 |
| Black   |      49 |
+———+———+

其中,WHERE從句不得不匹配每一個記錄,以檢查是否符合條件。對於這個較小的表也許感受不到太多的影響。可是對於一個較大的表,例如一個很是大的學校,咱們可能須要存儲成千上萬的記錄,這樣一個檢索的所花的時間是十分可觀的。
若是,咱們爲english列建立一個索引:sql

mysql>ALTER TABLE student ADD INDEX (english) ;
+——————-+
| index for english |
+——————-+
|                42 |
|                43 |
|                49 |
|                49 |
|                54 |
|                66 |
|                78 |
|                94 |
|                99 |
+——————-+

如上表,此索引存儲在索引文件中,包含表中每行的english列值,但此索引是在 english的基礎上排序的。如今,不須要逐行搜索全表查找匹配的條款,而是能夠利用索引進行查找。
假如咱們要查找分數小於60的全部行,那麼能夠掃描索引,結果得出5行。而後到達分數爲66的行,及Tom的記錄,這是一個比咱們正在查找的要大的值。
索引值是排序的,所以在讀到包含Tom的記錄時,咱們知道不會再有匹配的記錄,能夠退出了。
若是查找一個值,它在索引表中某個中間點之前不會出現,那麼也有找到其第一個匹配索引項的定位算法,而不用進行表的順序掃描(如二分查找法)。
這樣,能夠快速定位到第一個匹配的值,以節省大量搜索時間。數據庫利用了各類各樣的快速定位索引值的技術,這些技術是什麼並不重要,重要的是它們工做正常,索引技術是個好東西。
所以在執行下述查詢數據庫

mysql>SELECT name,english FROM user WHERE english<60;
其結果爲:
+———+———+
| name    | english |
+———+———+
| Stone   |      42 |
| William |      43 |
| Smith   |      49 |
| Black   |      49 |
| Marry   |      54 |
+———+———+

你應該能夠發現,這個結果與未索引english列以前的不一樣,它是排序的,緣由正式如上所述。緩存

===========================================================工具

索引對多個表查詢的影響性能

前面的討論描述了單表查詢中索引的好處,其中使用索引消除了全表掃描,極大地加快了搜索的速度。在執行涉及多個表的鏈接查詢時,索引甚至會更有價值。
在單個表的查詢中,每列須要查看的值的數目就是表中行的數目。而在多個表的查詢中,可能的組合數目極大,由於這個數目爲各表中行數之積。
假若有三個未索引的表 t一、t二、t3,分別只包含列 c一、c二、c3,每一個表分別由含有數值 1 到 1000 的 1000 行組成。
查找對應值相等的錶行組合的查詢以下所示:
此查詢的結果應該爲 1000 行,每一個組合包含 3 個相等的值。
如 果咱們在無索引的狀況下處理此查詢,則不可能知道哪些行包含那些值。所以,必須尋找出全部組合以便得出與 WHERE 子句相配的那些組合。可能的組合數目爲 1000×1000×1000(十億),比匹配數目多一百萬倍。不少工做都浪費了,而且這個查詢將會很是慢,即便在如像 MySQL 這樣快的數據庫中執行也會很慢。而這仍是每一個表中只有 1000 行的情形。
若是每一個表中有一百萬行時,將會怎樣?很顯然,這樣將會產生性能極爲低下的結果。
若是對每一個表進行索引,就能極大地加速查詢進程,
由於利用索引的查詢處理以下:
1) 以下從表 t1 中選擇第一行,查看此行所包含的值。
2) 使用表 t2 上的索引,直接跳到 t2 中與來自 t1 的值匹配的行。相似,利用表 t3 上的索引,直接跳到 t3 中與來自 t1 的值匹配的行。
3) 進到表 t1 的下一行並重復前面的過程直到 t1 中全部的行已經查過。
在此情形下,咱們仍然對錶 t1 執行了一個徹底掃描,但可以在表 t2 和 t3 上進行索引查找直接取出這些表中的行。從道理上說,這時的查詢比未用索引時要快一百萬倍。
如上所述,MySQL 利用索引加速了 WHERE 子句中與條件相配的行的搜索,或者說在執行鏈接時加快了與其餘表中的行匹配的行的搜索。
多列索引對查詢的影響
假定你發出下列SELECT語句:
mysql> SELECT * FROM tbl_name WHERE col1=val1 AND col2=val2;
若是一個多列索引存在於col1和col2上,適當的行能夠直接被取出。
若是分開的單行列索引存在於col1和col2上,優化器試圖經過決定哪一個索引將找到更少的行並來找出更具限制性的索引而且使用該索引取行。
你能夠這樣建立一個多列索引:
mysql>ALTER TABLE tbl_name ADD INDEX(col1,col2);
而你應該這樣建立分開的單行列索引:
mysql>ALTER TABLE tble_name ADD INDEX(col1);
mysql>ALTER TABLE tble_name ADD INDEX(col1); 
若是表有一個多列索引,任何最左面的索引前綴能被優化器使用以找出行。例如,若是你有一個3行列索引(col1,col2,col3),你已經索引了在(col1)、(col1,col2)和(col1,col2,col3)上的搜索能力。
若是列不構成索引的最左面前綴,MySQL不能使用一個部分的索引。
假定你下面顯示的SELECT語句:
mysql> SELECT * FROM tbl_name WHERE col1=val1;
mysql> SELECT * FROM tbl_name WHERE col2=val2;
mysql> SELECT * FROM tbl_name WHERE col2=val2 AND col3=val3; 
若是一個索引存在於(col一、col二、col3)上,只有上面顯示的第一個查詢使用索引。
第二個和第三個查詢確實包含索引的列,可是(col2)和(col二、col3)不是(col一、col二、col3)的最左面前綴。
若是LIKE參數是一個不以一個通配符字符起始的一個常數字符串,MySQL也爲LIKE比較使用索引。
例如,下列SELECT語句使用索引:
mysql> select * from tbl_name where key_col LIKE "Patrick%";
mysql> select * from tbl_name where key_col LIKE "Pat%_ck%"; 
在第一條語句中,只考慮有"Patrick" <= key_col < "Patricl"的行。在第二條語句中,只考慮有"Pat" <= key_col < "Pau"的行。
下列SELECT語句將不使用索引:
mysql> select * from tbl_name where key_col LIKE "%Patrick%";
mysql> select * from tbl_name where key_col LIKE other_col; 
在第一條語句中,LIKE值以一個通配符字符開始。在第二條語句中,LIKE值不是一個常數。
若是 column_name 是一個索引,使用column_name IS NULL的搜索將使用索引。
MySQL一般使用找出最少數量的行的索引。一個索引被用於你與下列操做符做比較的列:=、>、>=、<、<=、BETWEEN和一個有一個非通配符前綴象’something%’的LIKE的列。
對於一個多列索引,若是在WHERE子句的全部AND層次使用索引,將不使用來索引優化查詢。爲了可以使用索引優化查詢,必須把一個多列索引的前綴使用在一個AND條件組中。
下列WHERE子句使用索引:
... WHERE index_part1=1 AND index_part2=2
... WHERE index=1 OR A=10 AND index=2      /* index = 1 OR index = 2 */
... WHERE index_part1='hello' AND index_part_3=5
          /* optimized like "index_part1='hello'" */
這些WHERE子句不使用索引:
... WHERE index_part2=1 AND index_part3=2  /* index_part_1 is not used */
... WHERE index=1 OR A=10                  /* No index */
... WHERE index_part1=1 OR index_part2=10  /* No index spans all rows */優化

==========================================================spa

MySQL索引的做用
全部的MySQL索引(PRIMARY、UNIQUE和INDEX)在B樹中存儲。字符串是自動地壓縮前綴和結尾空間。
CREATE INDEX句法。
索引用於:
快速找出匹配一個WHERE子句的行。
在多個表的查詢時,執行鏈接時加快了與其餘表中的行匹配的行的搜索。
對特定的索引列找出MAX()或MIN()值。
若是排序或分組在一個可用索引的最左面前綴上進行(例如,ORDER BY key_part_1,key_part_2),排序或分組一個表。若是全部鍵值部分跟隨DESC,鍵以倒序被讀取。
在一些狀況中,一個查詢能被優化來檢索值,不用諮詢數據文件。
若是對某些表的全部使用的列是數字型的而且構成某些鍵的最左面前綴,爲了更快,值能夠從索引樹被檢索出來。
索引的弊端
一 般狀況下,若是 MySQL 可以知道怎樣用索引來更快地處理查詢,它就會這樣作。這表示,在大多數狀況下,若是您不對錶進行索引,則損害的是您本身的利益。能夠看出,做者描繪了索引 的諸多好處。但有不利之處嗎?是的,有。實際上,這些缺點被優勢所掩蓋了,但應該對它們有所瞭解。
首先,索引文件要佔磁盤空間。若是有大 量的索引,索引文件可能會比數據文件更快地達到最大的文件尺寸。其次,索引文件加快了檢索,但增長了插入和刪除,以及更新索引列中的值的時間(即,下降了 大多數涉及寫入的操做的時間),由於寫操做不只涉及數據行,並且還經常涉及索引。一個表擁有的索引越多,則寫操做的平均性能降低就越大。
在8.4.4節記錄裝載和修改的速度中,咱們將更爲詳細地介紹這些性能問題,並討論怎樣解決。code

===========================================================

選擇索引的準則
建立索引的語法已經在4.5索引屬性中進行了介紹。這裏,咱們假定您已經閱讀過該節。可是知道語法並不能幫助肯定表怎樣進行索引。要決定表怎樣進行索引須要考慮表的使用方式。
本節介紹一些關於怎樣肯定和挑選索引列的準則:
一、搜索的索引列,不必定是所要選擇的列
換句話說,最適合索引的列是出如今 WHERE 子句中的列,或鏈接子句中指定的列,而不是出如今 SELECT 關鍵字後的選擇列表中的列,例如:
SELECT
col_a                           ←不適合做索引列
FROM
Tbl1 LEFT JOIN tbl2
ON tbl1.col_b = tbl2.col_c      ←適合做索引列
WHERE
col_d = expr                    ←適合做索引列 
固然,所選擇的列和用於 WHERE 子句的列也多是相同的。關鍵是,列出如今選擇列表中不是該列應該索引的標誌。
出如今鏈接子句中的列或出如今形如 col1 = col2 的表達式中的列是很適合索引的列。查詢中的 col_b 和 col_c 就是這樣的例子。
若是 MySQL 能利用鏈接列來優化一個查詢,表示它經過消除全表掃描至關可觀地減小了錶行的組合。
二、使用唯一索引
考慮某列中值的分佈。對於唯一值的列,索引的效果最好,而具備多個重複值的列,其索引效果最差。例如,存放年齡的列具備不一樣值,很容易區分各行。
而用來記錄性別的列,只含有「M」和「F」,則對此列進行索引沒有多大用處(無論搜索哪一個值,都會得出大約一半的行)。
三、使用短索引
如 果對串列進行索引,應該指定一個前綴長度,只要有可能就應該這樣作。例如,若是有一個 CHAR(200) 列,若是在前 10 個或 20 個字符內,多數值是唯一的,那麼就不要對整個列進行索引。對前 10 個或 20 個字符進行索引可以節省大量索引空間,也可能會使查詢更快。
較小的索引涉及的磁盤 I/O 較少,較短的值比較起來更快。更爲重要的是,對於較短的鍵值,索引高速緩存中的塊能容納更多的鍵值,所以,MySQL 也能夠在內存中容納更多的值。這增長了找到行而不用讀取索引中較多塊的可能性。
(固然,應該利用一些常識。如僅用列值的第一個字符進行索引是不可能有多大好處的,由於這個索引中不會有許多不一樣的值。)
四、利用最左前綴
在建立一個 n 列的索引時,實際是建立了 MySQL 可利用的 n 個索引。多列索引可起幾個索引的做用,由於可利用索引中最左邊的列集來匹配行。這樣的列集稱爲最左前綴。
(這與索引一個列的前綴不一樣,索引一個列的前綴是利用該的前 n 個字符做爲索引值。)
假如一個表在分別名爲 state、city 和 zip 的三個列上有一個索引。
索引中的行是按 state/city/zip 的次序存放的,所以,索引中的行也會自動按 state/city 的順序和 state 的順序存放。這表示,即便在查詢中只指定 state 值或只指定 state 和 city 的值,MySQL 也能夠利用索引。
所以,此索引可用來搜索下列的列組合:
MySQL 不能使用不涉及左前綴的搜索。例如,若是按 city 或 zip 進行搜索,則不能使用該索引。若是要搜索某個州以及某個 zip 代碼(索引中的列1和列3),則此索引不能用於相應值的組合。可是,可利用索引來尋找與該州相符的行,以減小搜索範圍。
五、不要過分索引
不要覺得索引「越多越好」,什麼東西都用索引是錯的。每一個額外的索引都要佔用額外的磁盤空間,並下降寫操做的性能,這一點咱們前面已經介紹過。在修改表的內容時,索引必須進行更新,有時可能須要重構,所以,索引越多,所花的時間越長。
若是有一個索引不多利用或從不使用,那麼會沒必要要地減緩表的修改速度。此外,MySQL 在生成一個執行計劃時,要考慮各個索引,這也要費時間。
建立多餘的索引給查詢優化帶來了更多的工做。索引太多,也可能會使 MySQL 選擇不到所要使用的最好索引。只保持所需的索引有利於查詢優化。
若是想給已索引的表增長索引,應該考慮所要增長的索引是不是現有多列索引的最左索引。若是是,則就不要費力去增長這個索引了,由於已經有了。
六、考慮在列上進行的比較類型
索引可用於「<」、「<=」、「=」、「>=」、「>」和 BETWEEN 運算。在模式具備一個直接量前綴時,索引也用於 LIKE 運算。若是隻將某個列用於其餘類型的運算時(如 STRCMP( )),對其進行索引沒有價值。

=================================================================================================

總結: 本節介紹了索引在優化查詢中的做用,包括了索引優化查詢的原理,索引在各類狀況的檢索中的益處,也包括索引的的弊端:增長了存儲的空間,使裝載數據變慢。 索引是優化查詢的最經常使用也是最有效的的方法,一個數據表,尤爲是容量很大的表,創建合適的索引,會使查詢的速度提升很大。

相關文章
相關標籤/搜索