索引的三星原則
1.索引將相關的記錄放到一起,則獲得一星
2.如果索引中的數據順序和查找中的排列順序一致則獲得二星
3.如果索引中的列包含了查詢中的需要的全部列則獲得三星
多列索引
1.1、多個單列索引
很多人對多列索引的理解都不夠。一個常見的錯誤就是,為每個列建立獨立的索引,或者按照錯誤的順序創建多列索引。
我們會在稍后的章節中單獨討論索引列的順序問題。先來看第一個問題,為每個列創建獨立的索引,從SHOW CREATE TABLE 中很容易看到這種情況:
CREATE TABLE t( c1 INT,c2 INT , c3 INT ,KEY(c1),KEY(c2),KEY(c3) );
這種索引策略,一般是由於人們聽到一些專家諸如“把WHERE 條件里面的列都建上索引”這樣模糊的建議導致的。實際上這個建議是非常錯誤的。這樣一來最好的情況也只能是“一星”索引,其性能比起真正最有效的索引可能差幾個數量級。有時如果無法設計出一個“三星”索引,那么不如忽略掉WHERE 子句,集中精力優化索引列的順序,或者創建一個全覆蓋索引。
索引合並
在多個列上建立獨立的單列索引大部分情況下不能提高MySQL的查詢性能。MySQL5.0和更高的版本醫用了一種叫“索引合並”策略,一定程度上可以使用表上的多個單列索引來定位指定的行。更早版本的MySQL只能使用其中某一個單列索引,然而這種情況下沒有哪一個獨立索引是非常有效的。例如在film_actor在字段film_id和actor_id上各有一個單列索引。但是對於這個查詢WHERE 條件,這兩個單列索引都不是好的選擇:
SELECT film_id ,actor_id FROM film_actor WHERE actor_id=1 or film_id =1;
在老的MySQL版本中,MySQL對於這個查詢是會使用全表掃描的,除非改寫成如下的兩個查詢UNION的方式:
SELECT film_id ,actor_id FROM film_actor WHERE actor_id=1 UNION ALL SELECT film_id ,actor_id FROM film_actor WHERE film_id=1;
但是在MySQL5.0 和更高的版本中,查詢能夠同時使用者兩個單列索引進行掃掃描,並將結果進行合並。這種算法有三個變種:OR條件的聯合(union),AND條件的相交(intersection),組合前面兩種情況的聯合及相交。下面的查詢就是使用了兩個索引掃描的聯合,通過EXPLAIN中的Extra列可以看出這點:
EXPLAIN SELECT film_id,actor_id FROM film_actor WHERE actor_id=1 or film_id = 1 \G
MySQL會使用這類技術優化負責的查詢,所以在某些語句的EXTRA列中還可以看到嵌套操作。
索引合並策略有時候是一種優化的結構,但實際上更多的時候說明了表上的索引建的很糟糕:
當出現服務器對多個索引做相交操作(通常有多個AND條件),通常意味着需要一個包含所有相關列的多個索引,而不是獨立的單列索引。
當服務器需要對多個索引做聯合操作(通常有多個OR條件),通常需要耗費大量的cpu和內存資源在算法的緩沖,排序和合並的操作上。特別是當其中有些索引的選擇性不高。需要合並掃描返回大量數據的時候。
更重要的是,優化器不會吧這些成本算到“查詢成本”中,游虎丘只關心隨機頁面讀取。這會使得查詢成本被低估,導致該執行計划還不如直接走全表掃描。這樣做不但會消耗更多的cup和內存資源,還可能影響查詢的並發性,但如果是單獨魚腥這樣的查詢則往往會忽略對並發現的影響。通常來說,還不弱在MySQL4.1或更早的時代一樣,將查詢改寫成UNION的方式往往會更好。
如果在Explain語句中看到索引合並,應該好好檢查一下查詢和表的結構。也可以通過參數optimizer_switch來關閉索引合並功能。也可以使用IGNORE_INDEX提示讓優化器忽略掉某些索引。
==========================================================================================
為了提高搜索效率,我們需要考慮運用多列mysql數據庫索引。如果為firstname、lastname和age這三個列創建一個多列索引,MySQL只需一次檢索就能夠找出正確的結果!下面是創建這個復合索引的SQL命令:
ALTER TABLE people ADD INDEX fname_lname_age (firstname,lastname,age);
由於索引文件以B-樹格式保存,MySQL能夠立即轉到合適的firstname,然后再轉到合適的lastname,最后轉到合適的age。在沒有掃描數據文件任何一個記錄的情況下,MySQL就正確地找出了搜索的目標記錄!
那么,如果在firstname、lastname、age這三個列上分別創建單列索引,效果是否和創建一個firstname、lastname、age的多列MySQL數據庫索引一樣呢?答案是否定的,兩者完全不同。當我們執行查詢的時候,MySQL只能使用一個索引。如果你有三個單列的MySQL數據庫索引,MySQL會試圖選擇一個限制最嚴格的索引。
但是,即使是限制最嚴格的單列索引,它的限制能力也肯定遠遠低於firstname、lastname、age這三個列上的多列索引。
索引是快速搜索的關鍵。MySQL索引的建立對於MySQL的高效運行是很重要的。
1.2、復合索引
聯合索引又叫復合索引。對於復合索引:Mysql從左到右的使用索引中的字段,一個查詢可以只使用索引中的一部份,但只能是最左側部分。例如索引是key index (a,b,c)。 可以支持a | a,b| a,b,c 3種組合進行查找,但不支持 b,c進行查找 .當最左側字段是常量引用時,索引就十分有效。兩個或更多個列上的索引被稱作復合索引。
見《 mysql索引之四:復合索引之最左前綴原理,索引選擇性,索引優化策略之前綴索引》