( 轉 ) mysql復合索引、普通索引總結


對於復合索引:Mysql從左到右的使用索引中的字段,一個查詢可以只使用索引中的一部份,但只能是最左側部分。例如索引是key index (a,b,c). 可以支持a | a,b| a,b,c 3種組合進行查找,但不支持 b,c進行查找 .當最左側字段是常量引用時,索引就十分有效。下面用幾個例子對比查詢條件的不同對性能影響.

create table test(
a int,
b int,
c int,
KEY a(a,b,c)
);

優: select * from test where a=10 and b>50
差: select * from test where a50

優: select * from test where order by a
差: select * from test where order by b
差: select * from test where order by c

優: select * from test where a=10 order by a
優: select * from test where a=10 order by b
差: select * from test where a=10 order by c

優: select * from test where a>10 order by a
差: select * from test where a>10 order by b
差: select * from test where a>10 order by c

優: select * from test where a=10 and b=10 order by a
優: select * from test where a=10 and b=10 order by b
優: select * from test where a=10 and b=10 order by c

優: select * from test where a=10 and b=10 order by a
優: select * from test where a=10 and b>10 order by b
差: select * from test where a=10 and b>10 order by c

索引原則

1.索引越少越好
原因:主要在修改數據時,第個索引都要進行更新,降低寫速度。
2.最窄的字段放在鍵的左邊
3.避免file sort排序,臨時表和表掃描.

 

 

 

於是上網查了下相關的資料:(關於復合索引優化的)

兩個或更多個列上的索引被稱作復合索引。
利用索引中的附加列,您可以縮小搜索的范圍,但使用一個具有兩列的索引不同於使用兩個單獨的索引。復合索引的結構與電話簿類似,人名由姓和名構成,電話簿首先按姓氏對進行排序,然后按名字對有相同姓氏的人進行排序。如果您知道姓,電話簿將非常有用;如果您知道姓和名,電話簿則更為有用,但如果您只知道名不姓,電話簿將沒有用處。
所以說創建復合索引時,應該仔細考慮列的順序。對索引中的所有列執行搜索或僅對前幾列執行搜索時,復合索引非常有用;僅對后面的任意列執行搜索時,復合索引則沒有用處。
如:建立 姓名、年齡、性別的復合索引。



復合索引的建立原則:

如果您很可能僅對一個列多次執行搜索,則該列應該是復合索引中的第一列。如果您很可能對一個兩列索引中的兩個列執行單獨的搜索,則應該創建另一個僅包含第二列的索引。
如上圖所示,如果查詢中需要對年齡和性別做查詢,則應當再新建一個包含年齡和性別的復合索引。
包含多個列的主鍵始終會自動以復合索引的形式創建索引,其列的順序是它們在表定義中出現的順序,而不是在主鍵定義中指定的順序。在考慮將來通過主鍵執行的搜索,確定哪一列應該排在最前面。
請注意,創建復合索引應當包含少數幾個列,並且這些列經常在select查詢里使用。在復合索引里包含太多的列不僅不會給帶來太多好處。而且由於使用相當多的內存來存儲復合索引的列的值,其后果是內存溢出和性能降低。

         
復合索引對排序的優化:

復合索引只對和索引中排序相同或相反的order by 語句優化。
在創建復合索引時,每一列都定義了升序或者是降序。如定義一個復合索引:

Sql代碼   收藏代碼
  1. CREATE INDEX idx_example   
  2. ON table1 (col1 ASC, col2 DESC, col3 ASC)  

 
其中 有三列分別是:col1 升序,col2 降序, col3 升序。現在如果我們執行兩個查詢
1:Select col1, col2, col3 from table1 order by col1 ASC, col2 DESC, col3 ASC
  和索引順序相同
2:Select col1, col2, col3 from table1 order by col1 DESC, col2 ASC, col3 DESC
 和索引順序相反
查詢1,2 都可以別復合索引優化。
如果查詢為:
Select col1, col2, col3 from table1 order by col1 ASC, col2 ASC, col3 ASC
  排序結果和索引完全不同時,此時的查詢不會被復合索引優化。


查詢優化器在在where查詢中的作用:

如果一個多列索引存在於 列 Col1 和 Col2 上,則以下語句:Select   * from table where   col1=val1 AND col2=val2 查詢優化器會試圖通過決定哪個索引將找到更少的行。之后用得到的索引去取值。
1. 如果存在一個多列索引,任何最左面的索引前綴能被優化器使用。所以聯合索引的順序不同,影響索引的選擇,盡量將值少的放在前面。
如:一個多列索引為 (col1 ,col2, col3)
    那么在索引在列 (col1) 、(col1 col2) 、(col1 col2 col3) 的搜索會有作用。

 

Sql代碼   收藏代碼
  1. SELECT * FROM tb WHERE  col1 = val1  
  2. SELECT * FROM tb WHERE  col1 = val1 and col2 = val2  
  3. SELECT * FROM tb WHERE  col1 = val1 and col2 = val2  AND col3 = val3  

 

2. 如果列不構成索引的最左面前綴,則建立的索引將不起作用。
如:

Sql代碼   收藏代碼
  1. SELECT * FROM  tb WHERE  col3 = val3  
  2. SELECT * FROM  tb  WHERE  col2 = val2  
  3. SELECT * FROM  tb  WHERE  col2 = val2  and  col3=val3  

 
3. 如果一個 Like 語句的查詢條件不以通配符起始則使用索引。
如:%車 或 %車%   不使用索引。
    車%              使用索引。
索引的缺點:
1.       占用磁盤空間。
2.       增加了插入和刪除的操作時間。一個表擁有的索引越多,插入和刪除的速度越慢。如 要求快速錄入的系統不宜建過多索引。

下面是一些常見的索引限制問題

1、使用不等於操作符(<>, !=)
下面這種情況,即使在列dept_id有一個索引,查詢語句仍然執行一次全表掃描
select * from dept where staff_num <> 1000;
但是開發中的確需要這樣的查詢,難道沒有解決問題的辦法了嗎?
有!
通過把用 or 語法替代不等號進行查詢,就可以使用索引,以避免全表掃描:上面的語句改成下面這樣的,就可以使用索引了。

Sql代碼   收藏代碼
  1. select * from dept shere staff_num < 1000 or dept_id > 1000;  

 

2、使用 is null 或 is not null
使用 is null 或is nuo null也會限制索引的使用,因為數據庫並沒有定義null值。如果被索引的列中有很多null,就不會使用這個索引(除非索引是一個位圖索引,關於位圖索引,會在以后的blog文章里做詳細解釋)。在sql語句中使用null會造成很多麻煩。
解決這個問題的辦法就是:建表時把需要索引的列定義為非空(not null)

3、使用函數
如果沒有使用基於函數的索引,那么where子句中對存在索引的列使用函數時,會使優化器忽略掉這些索引。下面的查詢就不會使用索引:

Sql代碼   收藏代碼
  1. select * from staff where trunc(birthdate) = '01-MAY-82';  

 
但是把函數應用在條件上,索引是可以生效的,把上面的語句改成下面的語句,就可以通過索引進行查找。

Sql代碼   收藏代碼
  1. select * from staff where birthdate < (to_date('01-MAY-82') + 0.9999);  

 

4、比較不匹配的數據類型
比較不匹配的數據類型也是難於發現的性能問題之一。
下面的例子中,dept_id是一個varchar2型的字段,在這個字段上有索引,但是下面的語句會執行全表掃描。

Sql代碼   收藏代碼
  1. select * from dept where dept_id = 900198;  

 
這是因為oracle會自動把where子句轉換成to_number(dept_id)=900198,就是3所說的情況,這樣就限制了索引的使用。
把SQL語句改為如下形式就可以使用索引

Sql代碼   收藏代碼
  1. select * from dept where dept_id = '900198';  

 

 

還有就是參見 老王的blog上的文章

http://hi.baidu.com/thinkinginlamp/blog/item/9940728be3986015c8fc7a85.html

http://hi.baidu.com/thinkinginlamp/blog/item/a352918fe70d96fd503d925e.html

http://blog.csdn.net/fbd2011/article/details/7341312

http://blog.csdn.net/lovelyhermione/article/details/4580866

1、普通索引

  普通索引(由關鍵字KEY或INDEX定義的索引)的唯一任務是加快對數據的訪問速度。因此,應該只為那些最經常出現在查詢條件(WHEREcolumn=)或排序條件(ORDERBYcolumn)中的數據列創建索引。只要有可能,就應該選擇一個數據最整齊、最緊湊的數據列(如一個整數類型的數據列)來創建索引。

  2、唯一索引

  普通索引允許被索引的數據列包含重復的值。比如說,因為人有可能同名,所以同一個姓名在同一個“員工個人資料”數據表里可能出現兩次或更多次。

  如果能確定某個數據列將只包含彼此各不相同的值,在為這個數據列創建索引的時候就應該用關鍵字UNIQUE把它定義為一個唯一索引。這么做的好處:一是簡化了MySQL對這個索引的管理工作,這個索引也因此而變得更有效率;二是MySQL會在有新記錄插入數據表時,自動檢查新記錄的這個字段的值是否已經在某個記錄的這個字段里出現過了;如果是,MySQL將拒絕插入那條新記錄。也就是說,唯一索引可以保證數據記錄的唯一性。事實上,在許多場合,人們創建唯一索引的目的往往不是為了提高訪問速度,而只是為了避免數據出現重復。

  3、主索引

  在前面已經反復多次強調過:必須為主鍵字段創建一個索引,這個索引就是所謂的“主索引”。主索引與唯一索引的唯一區別是:前者在定義時使用的關鍵字是PRIMARY而不是UNIQUE。

  4、外鍵索引

  如果為某個外鍵字段定義了一個外鍵約束條件,MySQL就會定義一個內部索引來幫助自己以最有效率的方式去管理和使用外鍵約束條件。

  5、復合索引

  索引可以覆蓋多個數據列,如像INDEX(columnA,columnB)索引。這種索引的特點是MySQL可以有選擇地使用一個這樣的索引。如果查詢操作只需要用到columnA數據列上的一個索引,就可以使用復合索引INDEX(columnA,columnB)。不過,這種用法僅適用於在復合索引中排列在前的數據列組合。比如說,INDEX(A,B,C)可以當做A或(A,B)的索引來使用,但不能當做B、C或(B,C)的索引來使用。

  6、索引的長度

  在為CHAR和VARCHAR類型的數據列定義索引時,可以把索引的長度限制為一個給定的字符個數(這個數字必須小於這個字段所允許的最大字符個數)。這么做的好處是可以生成一個尺寸比較小、檢索速度卻比較快的索引文件。在絕大多數應用里,數據庫中的字符串數據大都以各種各樣的名字為主,把索引的長度設置為10~15個字符已經足以把搜索范圍縮小到很少的幾條數據記錄了。在為BLOB和TEXT類型的數據列創建索引時,必須對索引的長度做出限制;MySQL所允許的最大索引全文索引文本字段上的普通索引只能加快對出現在字段內容最前面的字符串(也就是字段內容開頭的字符)進行檢索操作。如果字段里存放的是由幾個、甚至是多個單詞構成的較大段文字,普通索引就沒什么作用了。這種檢索往往以的形式出現,這對MySQL來說很復雜,如果需要處理的數據量很大,響應時間就會很長。

  這類場合正是全文索引(full-textindex)可以大顯身手的地方。在生成這種類型的索引時,MySQL將把在文本中出現的所有單詞創建為一份清單,查詢操作將根據這份清單去檢索有關的數據記錄。全文索引即可以隨數據表一同創建,也可以等日后有必要時再使用下面這條命令添加:

  ALTERTABLEtablenameADDFULLTEXT(column1,column2)有了全文索引,就可以用SELECT查詢命令去檢索那些包含着一個或多個給定單詞的數據記錄了。下面是這類查詢命令的基本語法:

  SELECT*FROMtablename

  WHEREMATCH(column1,column2)AGAINST(‘word1','word2','word3’)

  上面這條命令將把column1和column2字段里有word1、word2和word3的數據記錄全部查詢出來。

 

總結:復合索引最牛C,所以你懂的。。!

 

原貼 : https://blog.csdn.net/csdn265/article/details/51889508


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM