用來加快查詢的技術不少,其中最重要的是索引。一般索引可以快速提升查詢速度。若是不適用索引,MYSQL必須從第一條記錄開始而後讀完整個表直到找出相關的行。表越大,花費的時間越多。但也不全是這樣。本文討論索引是什麼以及如何使用索引來改善性能,以及索引可能下降性能的狀況。html
MySQL官方對索引的定義爲:索引(Index)是幫助MySQL高效獲取數據的數據結構。提取句子主幹,就能夠獲得索引的本質:索引是數據結構。mysql
數據庫查詢是數據庫的最主要功能之一。咱們都但願查詢數據的速度能儘量的快,所以數據庫系統的設計者會從查詢算法的角度進行優化。最基本的查詢算法固然是順序查找(linear search),這種複雜度爲O(n)的算法在數據量很大時顯然是糟糕的,好在計算機科學的發展提供了不少更優秀的查找算法,例如二分查找(binary search)、二叉樹查找(binary tree search)等。若是稍微分析一下會發現,每種查找算法都只能應用於特定的數據結構之上,例如二分查找要求被檢索數據有序,而二叉樹查找只能應用於二叉查找樹上,可是數據自己的組織結構不可能徹底知足各類數據結構(例如,理論上不可能同時將兩列都按順序進行組織),因此,在數據以外,數據庫系統還維護着知足特定查找算法的數據結構,這些數據結構以某種方式引用(指向)數據,這樣就能夠在這些數據結構上實現高級查找算法。這種數據結構,就是索引。算法
索引是在MYSQL的存儲引擎層中實現的,而不是在服務層實現的。因此每種存儲引擎的索引都不必定徹底相同,也不是全部的存儲引擎都支持全部的索引類型。MYSQL目前提供了一下4種索引。sql
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 索引 | 不支持 | 暫不支持 | 不支持 |
注:不能用CREATE INDEX語句建立PRIMARY KEY索引
在執行CREATE TABLE語句時能夠建立索引,也能夠單獨用CREATE INDEX或ALTER TABLE來爲表增長索引。性能優化
1.ALTER TABLE - ALTER TABLE用來建立普通索引、UNIQUE索引或PRIMARY KEY索引。數據結構
2.CREATE INDEX - CREATE INDEX可對錶增長普通索引或UNIQUE索引。函數
可利用ALTER TABLE或DROP INDEX語句來刪除索引。相似於CREATE INDEX語句,DROP INDEX能夠在ALTER TABLE內部做爲一條語句處理,語法以下。性能
其中,前兩條語句是等價的,刪除掉table_name中的索引index_name。
第3條語句只在刪除PRIMARY KEY索引時使用,由於一個表只可能有一個PRIMARY KEY索引,所以不須要指定索引名。若是沒有建立PRIMARY KEY索引,但表具備一個或多個UNIQUE索引,則MySQL將刪除第一個UNIQUE索引。
若是從表中刪除了某列,則索引會受到影響。對於多列組合的索引,若是刪除其中的某列,則該列也會從索引中刪除。若是刪除組成索引的全部列,則整個索引將被刪除。
mysql> show index from tblname; mysql> show keys from tblname;
1. 較頻繁的做爲查詢條件的字段應該建立索引
2. 惟一性太差的字段不適合單首創建索引,即便頻繁做爲查詢條件
3. 更新很是頻繁的字段不適合建立索引
固然,並非存在更新的字段就適合建立索引,從斷定策略的用語上也能夠看出,是"很是頻繁"的字段。到底什麼樣的更新頻率應該算是"很是頻繁"呢?每秒?每分鐘?仍是每小時呢?說實話,還真難定義。不少時候是經過比較同一時間段內被更新的次數和利用該字段做爲條件的查詢次數來判斷的,若是經過該字段的查詢並非不少,可能幾個小時或是更長才會執行一次,更新反而比查詢更頻繁,那這樣的字段確定不適合建立索引。反之,若是咱們經過該字段的查詢比較頻繁,但更新並非特別多,好比查詢幾十次或更多才可能會產生一次更新,那我我的以爲更新所帶來的附加成本也是能夠接受的。
4. 不會出如今 WHERE 子句中的字段不應建立索引
見索引選擇性注意事項對選擇性解釋
;)使用短索引,若是對字符串列進行索引,應該指定一個前綴長度,可節省大量索引空間,提高查詢速度;
例如,有一個CHAR(200)列,若是在前10個或20個字符內,多數值是惟一的,那麼就不要對整個列進行索引。對前10個或者20個字符進行索引可以節省大量索引空間,也可能會使查詢更快。較小的索引涉及的磁盤IO較少,較短的值比較起來更快。更爲重要的是,對於較短的鍵值,因此高速緩存中的快能容納更多的鍵值,所以,MYSQL也能夠在內存中容納更多的值。這樣就增長了找到行而不用讀取索引中較多快的可能性。
利用最左前綴
既然索引能夠加快查詢速度,那麼是否是隻要是查詢語句須要,就建上索引?答案是否認的。由於索引雖然加快了查詢速度,但索引也是有代價的:索引文件自己要消耗存儲空間,同時索引會加劇插入、刪除和修改記錄時的負擔,另外,MySQL在運行時也要消耗資源維護索引,所以索引並非越多越好。
通常兩種狀況下不建議建索引:
表記錄比較少,例如一兩千條甚至只有幾百條記錄的表,不必建索引,讓查詢作全表掃描就行了;
至於多少條記錄纔算多,這個我的有我的的見解,我我的的經驗是以2000做爲分界線,記錄數不超過 2000能夠考慮不建索引,超過2000條能夠酌情考慮索引。
索引的選擇性較低。所謂索引的選擇性(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),因此實在沒有什麼必要爲其單獨建索引。
MySQL只對一下操做符才使用索引:<,<=,=,>,>=,between,in
, 以及某些時候的like(不以通配符%或_開頭的情形)
。
不要過分索引,只保持所需的索引。每一個額外的索引都要佔用額外的磁盤空間,並下降寫操做的性能。 在修改表的內容時,索引必須進行更新,有時可能須要重構,所以,索引越多,所花的時間越長。
索引的益處已經清楚了,可是咱們不能只看到這些益處,並認爲索引是解決查詢優化的聖經,只要發現 查詢運行不夠快就將 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 所佔用的空間也會不斷增長,因此索引還會帶來存儲空間資源消耗的增長。