天天看點

MySQL 索引管理與執行計劃

  索引是對資料庫表中一列或多列的值進行排序的一種結構,使用索引可快速通路資料庫表中的特定資訊。如果想按特定職員的姓來查找他或她,則與在表中搜尋所有的行相比,索引有助于更快地擷取資訊。

  索引的一個主要目的就是加快檢索表中資料的方法,亦即能協助資訊搜尋者盡快的找到符合限制條件的記錄ID的輔助資料結構。

MySQL 索引管理與執行計劃

  唯一索引是不允許其中任何兩行具有相同索引值的索引。當現有資料中存在重複的鍵值時,大多數資料庫不允許将新建立的唯一索引與表一起儲存。資料庫還可能防止添加将在表中建立重複鍵值的新資料。

  例如,如果在employee表中職員的姓(lname)上建立了唯一索引,則任何兩個員工都不能同姓。

  資料庫表經常有一列或多列組合,其值唯一辨別表中的每一行。該列稱為表的主鍵。在資料庫關系圖中為表定義主鍵将自動建立主鍵索引,主鍵索引是唯一索引的特定類型。

  該索引要求主鍵中的每個值都唯一。當在查詢中使用主鍵索引時,它還允許對資料的快速通路。

  在聚集索引中,表中行的實體順序與鍵值的邏輯(索引)順序相同。一個表隻能包含一個聚集索引。如果某索引不是聚集索引,則表中行的實體順序與鍵值的邏輯順序不比對。與非聚集索引相比,聚集索引通常提供更快的資料通路速度。

  聚集索引和非聚集索引的差別,如字典預設按字母順序排序,讀者如知道某個字的讀音可根據字母順序快速定位。是以聚集索引和表的内容是在一起的。如讀者需查詢某個生僻字,則需按字典前面的索引,舉例按偏旁進行定位,找到該字對應的頁數,再打開對應頁數找到該字。

  這種通過兩個地方而查詢到某個字的方式就如非聚集索引。

  可以基于資料庫表中的單列或多列建立索引。多列索引可以區分其中一列可能有相同值的行。如果經常同時搜尋兩列或多列或按兩列或多列排序時,索引也很有幫助。

  例如,如果經常在同一查詢中為姓和名兩列設定判據,那麼在這兩列上建立多列索引将很有意義。

  檢查查詢的WHERE和JOIN子句。在任一子句中包括的每一列都是索引可以選擇的對象。對新索引進行試驗以檢查它對運作查詢性能的影響。考慮已在表上建立的索引數量。最好避免在單個表上有很多索引。

  檢查已在表上建立的索引的定義。最好避免包含共享列的重疊索引。

檢查某列中唯一資料值的數量,并将該數量與表中的行數進行比較。比較的結果就是該列的可選擇性,這有助于确定該列是否适合建立索引,如果适合,确定索引的類型。

MySQL 索引管理與執行計劃

  B樹的搜尋,從根結點開始,如果查詢的關鍵字與結點的關鍵字相等,那麼就命中;否則,如果查詢關鍵字比結點關鍵字小,就進入左邊;如果比結點關鍵字大,就進入右邊;如果左邊或右邊的指針為空,則報告找不到相應的關鍵。

如果B樹的所有非葉子結點的左右子樹的結點數目均保持差不多(平衡),那麼B樹的搜尋性能逼近二分查找;但它比連續記憶體空間的二分查找的優點是,改變B樹結構(插入與删除結點)不需要移動大段的記憶體資料,甚至通常是常數開銷。

    B+樹是B-樹的變體,也是一種多路搜尋樹:

MySQL 索引管理與執行計劃

   B+的搜尋與B-樹也基本相同,差別是B+樹隻有達到葉子結點才命中(B-樹可以在非葉子結點命中),其性能也等價于在關鍵字全集做一次二分查找;

       B+的特性:

  哈希索引隻有Memory, NDB兩種引擎支援,Memory引擎預設支援哈希索引,如果多個hash值相同,出現哈希碰撞,那麼索引以連結清單方式存儲。

  但是,Memory引擎表隻對能夠适合機器的記憶體切實有限的資料集。

  要使InnoDB或MyISAM支援哈希索引,可以通過僞哈希索引來實作,叫自适應哈希索引。

  主要通過增加一個字段,存儲hash值,将hash值建立索引,在插入和更新的時候,建立觸發器,自動添加計算後的hash到表裡。

  索引建立在表的列上(字段)的。

  在where後面的列建立索引才會加快查詢速度。

  pages<---索引(屬性)<----查資料。

添加索引的方法:

文法格式:

建立普通索引方法一:

建立普通索引方法二:

主鍵索引

  隻能有一個主鍵。

  主鍵索引:列的内容是唯一值,例如學号.

  表建立的時候至少要有一個主鍵索引,最好和業務無關。

普通索引

  加快查詢速度,工作中優化資料庫的關鍵。

  在合适的列上建立索引,讓資料查詢更高效。

用了索引,查一堆内容。

  在where條件關鍵字後面的列建立索引才會加快查詢速度.

唯一索引

  内容唯一,但不是主鍵。

  建立表時

  建立表後增加

增加自增主鍵

字首索引:根據字段的前N個字元建立索引

聯合索引:多個字段建立一個索引。

  特點:字首生效特性。

  原則:把最常用來作為條件查詢的列放在前面。

示例:

建立表

建立聯合索引

   檢視索引的類型

建立唯一鍵索引

   檢視資料表

  聯合主鍵是聯合索引的特殊形式

字首加聯合索引

  1、把一個大的不使用索引的SQL語句按照功能進行拆分

  2、長的SQL語句無法使用索引,能不能變成2條短的SQL語句讓它分别使用上索引。

  3、對SQL語句功能的拆分和修改

  4、減少“爛”SQL由運維(DBA)和開發交流(确認),共同确定如何改,最終由DBA執行

  5、制定開發流程

  1、唯一值少的列上不适合建立索引或者建立索引效率低。例如:性别列

  2、小表可以不建立索引,100條記錄。

  3、對于資料倉庫,大量全表掃描的情況,建索引反而會慢

  1、找到慢SQL。

    記錄慢查詢日志。

  2、explain select句,條件列多。

  3、檢視表的唯一值數量:

    條件列多。可以考慮建立聯合索引。

  4、建立索引(流量低谷)

  5、拆開語句(和開發)。

  6、like '%%'不用mysql

  7、進行判斷重複的行數

檢視行數:

檢視去重後的行數:

  在工作中,我們用于捕捉性能問題最常用的就是打開慢查詢,定位執行效率差的SQL,那麼當我們定位到一個SQL以後還不算完事,我們還需要知道該SQL的執行計劃,比如是全表掃描,還是索引掃描,這些都需要通過EXPLAIN去完成。

  EXPLAIN指令是檢視優化器如何決定執行查詢的主要方法。可以幫助我們深入了解MySQL的基于開銷的優化器,還可以獲得很多可能被優化器考慮到的通路政策的細節,以及當運作SQL語句時哪種政策預計會被優化器采用。

  需要注意的是,生成的QEP并不确定,它可能會根據很多因素發生改變。MySQL不會将一個QEP和某個給定查詢綁定,QEP将由SQL語句每次執行時的實際情況确定,即便使用存儲過程也是如此。盡管在存儲過程中SQL語句都是預先解析過的,但QEP仍然會在每次調用存儲過程的時候才被确定。

  SQL_NO_CACHE的作用是禁止緩存查詢結果。

使用where條件查找

  包含一組數字,表示查詢中執行select子句或操作表的順序

【示例一】id相同,執行順序由上至下

【示例二】如果是子查詢,id的序号會遞增,id值越大優先級越高,越先被執行

【示例三】id如果相同,可以認為是一組,從上往下順序執行;在所有組中,id值越大,優先級越高,越先執行

說明:

【示例】

内容說明:

  表示MySQL在表中找到所需行的方式,又稱“通路類型”,常見類型如下:

  從左到右,性能從最差到最好

【示例一】ALL:Full Table Scan, MySQL将周遊全表以找到比對的行

【示例二】index:Full Index Scan,index與ALL差別為index類型隻周遊索引樹

【示例三】range:索引範圍掃描,對索引的掃描開始于某一點,傳回比對值域的行。

顯而易見的索引範圍掃描是帶有between或者where子句裡帶有<, >查詢。當mysql使用索引去查找一系列值時,例如IN()和OR清單,也會顯示range(範圍掃描),當然性能上面是有差異的。

【示例四】ref:使用非唯一索引掃描或者唯一索引的字首掃描,傳回比對某個單獨值的記錄行

【示例五】eq_ref:類似ref,差別就在使用的索引是唯一索引,對于每個索引鍵值,表中隻有一條記錄比對,簡單來說,就是多表連接配接中使用primary key或者 unique key作為關聯條件。

【示例六】const、system:當MySQL對查詢某部分進行優化,并轉換為一個常量時,使用這些類型通路。

  如将主鍵置于where清單中,MySQL就能将該查詢轉換為一個常量

  注:system是const類型的特例,當查詢的表隻有一行的情況下,使用system

【示例七】NULL:MySQL在優化過程中分解語句,執行時甚至不用通路表或索引,   例如從一個索引列裡選取最小值可以通過單獨索引查找完成。

  指出MySQL能使用哪個索引在表中找到記錄,查詢涉及到的字段上若存在索引,則該索引将被列出,但不一定被查詢使用

  顯示MySQL在查詢中實際使用的索引,若沒有使用索引,顯示為NULL

  表示索引中使用的位元組數,可通過該列計算查詢中使用的索引的長度(key_len顯示的值為索引字段的最大可能長度,并非實際使用長度,即key_len是根據表定義計算而得,不是通過表内檢索出的)。

  表示上述表的連接配接比對條件,即哪些列或常量被用于查找索引列上的值。

  表示MySQL根據表統計資訊及索引選用情況,估算的找到所需的記錄所需要讀取的行數。

  包含不适合在其他列中顯示但十分重要的額外資訊

【示例一】Using index

該值表示相應的select操作中使用了覆寫索引(Covering Index)

    覆寫索引(Covering Index)

    MySQL可以利用索引傳回select清單中的字段,而不必根據索引再次讀取資料檔案

    包含所有滿足查詢需要的資料的索引稱為覆寫索引(Covering Index)

    注意:如果要使用覆寫索引,一定要注意select清單中隻取出需要的列,不可select *,因為如果将所有字段一起做索引會導緻索引檔案過大,查詢性能下降

【示例二】Using where

  表示mysql伺服器将在存儲引擎檢索行後再進行過濾。許多where條件裡涉及索引中的列,當(并且如果)它讀取索引時,就能被存儲引擎檢驗,是以不是所有帶where字句的查詢都會顯示"Using where"。

  有時"Using where"的出現就是一個暗示:查詢可受益與不同的索引。

【示例三】Using temporary

  表示MySQL需要使用臨時表來存儲結果集,常見于排序和分組查詢

  這個值表示使用了内部臨時(基于記憶體的)表。一個查詢可能用到多個臨時表。有很多原因都會導緻MySQL在執行查詢期間建立臨時表。兩個常見的原因是在來自不同表的上使用了DISTINCT,或者使用了不同的ORDER BY和GROUP BY列。可以強制指定一個臨時表使用基于磁盤的MyISAM存儲引擎。這樣做的原因主要有兩個:

    1)内部臨時表占用的空間超過min(tmp_table_size,max_heap_table_size)系統變量的限制

    2)使用了TEXT/BLOB 列

【示例四】Using filesort

  MySQL中無法利用索引完成的排序操作稱為“檔案排序”

【示例五】Using join buffer

  該值強調了在擷取連接配接條件時沒有使用索引,并且需要連接配接緩沖區來存儲中間結果。

  如果出現了這個值,那應該注意,根據查詢的具體情況可能需要添加索引來改進能。

删除t1索引

删除t2索引

經常查找

【示例六】Impossible where

  這個值強調了where語句會導緻沒有符合條件的行。

【示例七】Select tables optimized away

  這個值意味着僅通過使用索引,優化器可能僅從聚合函數結果中傳回一行.

【示例八】Index merges

  當MySQL 決定要在一個給定的表上使用超過一個索引的時候,就會出現以下格式中的一個,詳細說明使用的索引以及合并的類型。

  EXPLAIN不會告訴你關于觸發器、存儲過程的資訊或使用者自定義函數對查詢的影響情況。

  EXPLAIN不考慮各種Cache。

  EXPLAIN不能顯示MySQL在執行查詢時所作的優化工作。

  部分統計資訊是估算的,并非精确值。

  EXPALIN隻能解釋SELECT操作,其他操作要重寫為SELECT後檢視執行計劃。

  1) 沒有查詢條件,或者查詢條件沒有建立索引

  2) 在查詢條件上沒有使用引導列

  3) 查詢的數量是大表的大部分,應該是30%以上。

  4) 索引本身失效

  5) 查詢條件使用函數在索引列上,或者對索引列進行運算,運算包括(+,-,*,/,! 等)

    錯誤的例子:select * from test where id-1=9; 正确的例子:select * from test where id=10;

  6) 對小表查詢

  7) 提示不使用索引

  8) 統計資料不真實

  9) CBO計算走索引花費過大的情況。其實也包含了上面的情況,這裡指的是表占有的block要比索引小。

  10)隐式轉換導緻索引失效.這一點應當引起重視.也是開發中經常會犯的錯誤.

    由于表的字段tel_num定義為varchar2(20),但在查詢時把該字段作為number類型以where條件傳給資料庫,這樣會導緻索引失效.

      錯誤的例子:select * from test where tel_nume=13333333333;

      正确的例子:select * from test where tel_nume='13333333333';

  11) 注意使用的特殊符号

        1,<>  ,!=

        2,單獨的>,<,(有時會用到,有時不會)

  12)like "%_" 百分号在前.

      select * from t1  where name like 'linux教育訓練%';

  13) not in ,not exist.

  14)  in  盡量改成 union 。

  15)當變量采用的是times變量,而表的字段采用的是date變量時.或相反情況。

  16)B-tree索引is null不會走,is not null會走,位圖索引 is null,is not null 都會走 。

  17)聯合索引 is not null 隻要在建立的索引列(不分先後)都會走,

  in null時 必須要和建立索引第一列一起使用,當建立索引第一位置條件是is null 時,其他建立索引的列可以是is null(但必須在所有列 都滿足is null的時候),或者=一個值;

  當建立索引的第一位置是=一個值時,其他索引列可以是任何情況(包括is null =一個值),以上兩種情況索引都會走。其他情況不會走。

  為了使索引的使用效率更高,在建立索引時,必須考慮在哪些字段上建立索引和建立什麼類型的索引。

1.選擇唯一性索引

  唯一性索引的值是唯一的,可以更快速的通過該索引來确定某條記錄。

  例如,學生表中學号是具有唯一性的字段。為該字段建立唯一性索引可以很快的确定某個學生的資訊。如果使用姓名的話,可能存在同名現象,進而降低查詢速度。

2.為經常需要排序、分組和聯合操作的字段建立索引

  經常需要ORDER BY、GROUP BY、DISTINCT和UNION等操作的字段,排序操作會浪費很多時間。

如果為其建立索引,可以有效地避免排序操作。

3.為常作為查詢條件的字段建立索引

  如果某個字段經常用來做查詢條件,那麼該字段的查詢速度會影響整個表的查詢速度。是以,

  為這樣的字段建立索引,可以提高整個表的查詢速度。

4.限制索引的數目

  索引的數目不是越多越好。每個索引都需要占用磁盤空間,索引越多,需要的磁盤空間就越大。修改表時,對索引的重構和更新很麻煩。越多的索引,會使更新表變得很浪費時間。

5.盡量使用資料量少的索引

  如果索引的值很長,那麼查詢的速度會受到影響。例如,對一個CHAR(100)類型的字段進行全文檢索需要的時間肯定要比對CHAR(10)類型的字段需要的時間要多。

6.盡量使用字首來索引

  如果索引字段的值很長,最好使用值的字首來索引。例如,TEXT和BLOG類型的字段,進行全文檢索會很浪費時間。如果隻檢索字段的前面的若幹個字元,這樣可以提高檢索速度。

7.删除不再使用或者很少使用的索引

  表中的資料被大量更新,或者資料的使用方式被改變後,原有的一些索引可能不再需要。資料庫管理者應當定期找出這些索引,将它們删除,進而減少索引對更新操作的影響。

8.小表不應建立索引

  包含大量的列并且不需要搜尋非空值的時候可以考慮不建索引