MYSQL-索引

概述

用來加快查詢的技術不少,其中最重要的是索引。一般索引可以快速提升查詢速度。若是不適用索引,MYSQL必須從第一條記錄開始而後讀完整個表直到找出相關的行。表越大,花費的時間越多。但也不全是這樣。本文討論索引是什麼以及如何使用索引來改善性能,以及索引可能下降性能的狀況。html

索引的本質

MySQL官方對索引的定義爲:索引(Index)是幫助MySQL高效獲取數據的數據結構。提取句子主幹,就能夠獲得索引的本質:索引是數據結構。mysql

數據庫查詢是數據庫的最主要功能之一。咱們都但願查詢數據的速度能儘量的快,所以數據庫系統的設計者會從查詢算法的角度進行優化。最基本的查詢算法固然是順序查找(linear search),這種複雜度爲O(n)的算法在數據量很大時顯然是糟糕的,好在計算機科學的發展提供了不少更優秀的查找算法,例如二分查找(binary search)、二叉樹查找(binary tree search)等。若是稍微分析一下會發現,每種查找算法都只能應用於特定的數據結構之上,例如二分查找要求被檢索數據有序,而二叉樹查找只能應用於二叉查找樹上,可是數據自己的組織結構不可能徹底知足各類數據結構(例如,理論上不可能同時將兩列都按順序進行組織),因此,在數據以外,數據庫系統還維護着知足特定查找算法的數據結構,這些數據結構以某種方式引用(指向)數據,這樣就能夠在這些數據結構上實現高級查找算法。這種數據結構,就是索引。算法

索引的存儲分類

索引是在MYSQL的存儲引擎層中實現的,而不是在服務層實現的。因此每種存儲引擎的索引都不必定徹底相同,也不是全部的存儲引擎都支持全部的索引類型。MYSQL目前提供了一下4種索引。sql

  • B-Tree 索引:最多見的索引類型,大部分引擎都支持B樹索引。
  • HASH 索引:只有Memory引擎支持,使用場景簡單。
  • R-Tree 索引(空間索引):空間索引是MyISAM的一種特殊索引類型,主要用於地理空間數據類型。
  • Full-text (全文索引):全文索引也是MyISAM的一種特殊索引類型,主要用於全文索引,InnoDB從MYSQL5.6版本提供對全文索引的支持。

Mysql目前不支持函數索引,可是能對列的前面某一部分進行索引,例如標題title字段,能夠只取title的前10個字符進行索引,這個特性能夠大大縮小索引文件的大小,但前綴索引也有缺點,在排序Order By和分組Group By 操做的時候沒法使用。用戶在設計表結構的時候也能夠對文本列根據此特性進行靈活設計。
語法:create index idx_title on film (title(10))數據庫

MyISAM、InnoDB引擎、Memory三個經常使用引擎類型比較緩存

索引 MyISAM引擎 InnoDB引擎 Memory引擎
B-Tree 索引 支持 支持 支持
HASH 索引 不支持 不支持 支持
R-Tree 索引 支持 不支持 不支持
Full-text 索引 不支持 暫不支持 不支持

B-TREE索引類型

  • 普通索引
    這是最基本的索引類型,並且它沒有惟一性之類的限制。普通索引能夠經過如下幾種方式建立:
    (1)建立索引: CREATE INDEX 索引名 ON 表名(列名1,列名2,...);
    (2)修改表: ALTER TABLE 表名ADD INDEX 索引名 (列名1,列名2,...);
    (3)建立表時指定索引:CREATE TABLE 表名 ( [...], INDEX 索引名 (列名1,列名 2,...) );
  • UNIQUE索引
    表示惟一的,不容許重複的索引,若是該字段信息保證不會重複例如身份證號用做索引時,可設置爲unique:
    (1)建立索引:CREATE UNIQUE INDEX 索引名 ON 表名(列的列表);
    (2)修改表:ALTER TABLE 表名ADD UNIQUE 索引名 (列的列表);
    (3)建立表時指定索引:CREATE TABLE 表名( [...], UNIQUE 索引名 (列的列表) );
  • 主鍵:PRIMARY KEY索引
    主鍵是一種惟一性索引,但它必須指定爲「PRIMARY KEY」。
    (1)主鍵通常在建立表的時候指定:「CREATE TABLE 表名( [...], PRIMARY KEY (列的列表) ); 」。
    (2)可是,咱們也能夠經過修改表的方式加入主鍵:「ALTER TABLE 表名ADD PRIMARY KEY (列的列表); 」。
    每一個表只能有一個主鍵。 (主鍵至關於聚合索引,是查找最快的索引)
    注:不能用CREATE INDEX語句建立PRIMARY KEY索引

索引的設置語法

一 設置索引

在執行CREATE TABLE語句時能夠建立索引,也能夠單獨用CREATE INDEX或ALTER TABLE來爲表增長索引。性能優化

1.ALTER TABLE - ALTER TABLE用來建立普通索引UNIQUE索引PRIMARY KEY索引數據結構

  • ALTER TABLE table_name ADD INDEX index_name (column_list)
  • ALTER TABLE table_name ADD UNIQUE (column_list)
  • ALTER TABLE table_name ADD PRIMARY KEY (column_list)

2.CREATE INDEX - CREATE INDEX可對錶增長普通索引或UNIQUE索引。函數

  • CREATE INDEX index_name ON table_name (column_list)
  • CREATE UNIQUE INDEX index_name ON table_name (column_list)

二 刪除索引

可利用ALTER TABLE或DROP INDEX語句來刪除索引。相似於CREATE INDEX語句,DROP INDEX能夠在ALTER TABLE內部做爲一條語句處理,語法以下。性能

  • DROP INDEX index_name ON talbe_name
  • ALTER TABLE table_name DROP INDEX index_name
  • ALTER TABLE table_name DROP PRIMARY KEY

其中,前兩條語句是等價的,刪除掉table_name中的索引index_name。
第3條語句只在刪除PRIMARY KEY索引時使用,由於一個表只可能有一個PRIMARY KEY索引,所以不須要指定索引名。若是沒有建立PRIMARY KEY索引,但表具備一個或多個UNIQUE索引,則MySQL將刪除第一個UNIQUE索引。

若是從表中刪除了某列,則索引會受到影響。對於多列組合的索引,若是刪除其中的某列,則該列也會從索引中刪除。若是刪除組成索引的全部列,則整個索引將被刪除。

三 查看索引

mysql> show index from tblname;
mysql> show keys from tblname;
  • Table:表的名稱
  • Non_unique:若是索引不能包括重複詞,則爲0。若是能夠,則爲1
  • Key_name:索引的名稱
  • Seq_in_index:索引中的列序列號,從1開始
  • Column_name:列名稱
  • Collation:列以什麼方式存儲在索引中。在MySQL中,有值‘A’(升序)或NULL(無分類)。
  • Cardinality:索引中惟一值的數目的估計值。經過運行ANALYZE TABLE或myisamchk -a能夠更新。基數根據被存儲爲整數的統計數據來計數,因此即便對於小型表,該值也沒有必要是精確的。基數越大,當進行聯合時,MySQL使用該索引的機會就越大。
  • Sub_part:若是列只是被部分地編入索引,則爲被編入索引的字符的數目。若是整列被編入索引,則爲NULL。
  • Packed:指示關鍵字如何被壓縮。若是沒有被壓縮,則爲NULL。
  • Null:若是列含有NULL,則含有YES。若是沒有,則該列含有NO。
  • Index_type:用過的索引方法(BTREE, FULLTEXT, HASH, RTREE)。
  • Comment:更多評註。

索引選擇性

一 索引選擇原則

1. 較頻繁的做爲查詢條件的字段應該建立索引
2. 惟一性太差的字段不適合單首創建索引,即便頻繁做爲查詢條件
3. 更新很是頻繁的字段不適合建立索引

固然,並非存在更新的字段就適合建立索引,從斷定策略的用語上也能夠看出,是"很是頻繁"的字段。到底什麼樣的更新頻率應該算是"很是頻繁"呢?每秒?每分鐘?仍是每小時呢?說實話,還真難定義。不少時候是經過比較同一時間段內被更新的次數和利用該字段做爲條件的查詢次數來判斷的,若是經過該字段的查詢並非不少,可能幾個小時或是更長才會執行一次,更新反而比查詢更頻繁,那這樣的字段確定不適合建立索引。反之,若是咱們經過該字段的查詢比較頻繁,但更新並非特別多,好比查詢幾十次或更多才可能會產生一次更新,那我我的以爲更新所帶來的附加成本也是能夠接受的。

4. 不會出如今 WHERE 子句中的字段不應建立索引

二 索引選擇原則細述

  • 性能優化過程當中,選擇在哪一個列上建立索引是最很是重要的。能夠考慮使用索引的主要有 兩種類型的列:在where子句中出現的列在join子句中出現的列,而不是在SELECT關鍵字後選擇列表的列;
  • 索引列的基數越大,索引的效果越好。例如,存放出生日期的列具備不一樣的值,很容易區分行,而用來記錄性別的列,只有"M"和"F",則對此進行索引沒有多大用處,所以無論搜索哪一個值,都會得出大約一半的行,( 見索引選擇性注意事項對選擇性解釋;)
  • 使用短索引,若是對字符串列進行索引,應該指定一個前綴長度,可節省大量索引空間,提高查詢速度;

    例如,有一個CHAR(200)列,若是在前10個或20個字符內,多數值是惟一的,那麼就不要對整個列進行索引。對前10個或者20個字符進行索引可以節省大量索引空間,也可能會使查詢更快。較小的索引涉及的磁盤IO較少,較短的值比較起來更快。更爲重要的是,對於較短的鍵值,因此高速緩存中的快能容納更多的鍵值,所以,MYSQL也能夠在內存中容納更多的值。這樣就增長了找到行而不用讀取索引中較多快的可能性。

  • 利用最左前綴

三 索引選擇注意事項

既然索引能夠加快查詢速度,那麼是否是隻要是查詢語句須要,就建上索引?答案是否認的。由於索引雖然加快了查詢速度,但索引也是有代價的:索引文件自己要消耗存儲空間,同時索引會加劇插入、刪除和修改記錄時的負擔,另外,MySQL在運行時也要消耗資源維護索引,所以索引並非越多越好。

通常兩種狀況下不建議建索引:

  1. 表記錄比較少,例如一兩千條甚至只有幾百條記錄的表,不必建索引,讓查詢作全表掃描就行了;

    至於多少條記錄纔算多,這個我的有我的的見解,我我的的經驗是以2000做爲分界線,記錄數不超過 2000能夠考慮不建索引,超過2000條能夠酌情考慮索引。

  2. 索引的選擇性較低。所謂索引的選擇性(Selectivity),是指不重複的索引值(也叫基數,Cardinality)與表記錄數(#T)的比值:
    Index Selectivity = Cardinality / #T
    顯然選擇性的取值範圍爲(0, 1],選擇性越高的索引價值越大,這是由B+Tree的性質決定的。例如,上文用到的employees.titles表,若是title字段常常被單獨查詢,是否須要建索引,咱們看一下它的選擇性:

    SELECT count(DISTINCT(title))/count(*) AS Selectivity FROM employees.titles;

    +-------------+
    | Selectivity |
    +-------------+
    |      0.0000 |
    +-------------+

    title的選擇性不足0.0001(精確值爲0.00001579),因此實在沒有什麼必要爲其單獨建索引。

  3. MySQL只對一下操做符才使用索引:<,<=,=,>,>=,between,in, 以及某些時候的like(不以通配符%或_開頭的情形)

  4. 不要過分索引,只保持所需的索引。每一個額外的索引都要佔用額外的磁盤空間,並下降寫操做的性能。 在修改表的內容時,索引必須進行更新,有時可能須要重構,所以,索引越多,所花的時間越長。

四 索引的弊端

索引的益處已經清楚了,可是咱們不能只看到這些益處,並認爲索引是解決查詢優化的聖經,只要發現 查詢運行不夠快就將 WHERE 子句中的條件所有放在索引中。

確實,索引可以極大地提升數據檢索效率,也可以改善排序分組操做的性能,但有不能忽略的一個問題就是索引是徹底獨立於基礎數據以外的一部分數據。假設在Table ta 中的Column ca 建立了索引 idx_ta_ca,那麼任何更新 Column ca 的操做,MySQL在更新表中 Column ca的同時,都需要更新Column ca 的索引數據,調整由於更新帶來鍵值變化的索引信息。而若是沒有對 Column ca 進行索引,MySQL要作的僅僅是更新表中 Column ca 的信息。這樣,最明顯的資源消耗就是增長了更新所帶來的 IO 量和調整索引所致的計算量。此外,Column ca 的索引idx_ta_ca需要佔用存儲空間,並且隨着 Table ta 數據量的增長,idx_ta_ca 所佔用的空間也會不斷增長,因此索引還會帶來存儲空間資源消耗的增長。

引用

相關文章
相關標籤/搜索