這是一篇譯文,原文請點擊:英文原文地址html
理解索引對開發和dba來講都是極其重要mysql
差勁的索引對產品問題負至關大的一部分責任web
索引不是多麼高深的問題sql
理解索引chrome
爲你的應用建立最佳索引數據庫
擁抱MySQL的限制dom
索引有什麼用函數
爲從數據庫讀取數據加速工具
強制約束 (惟一索引 UNIQUE, 外鍵 FOREIGN KEY)oop
沒有任何索引的狀況下查詢頁能正常運行
可是那可能須要執行很長的時間
BTREE索引 – mysql中主要的索引類型
RTREE索引 – 只有MyISAM支持, 用於GIS
HASH 索引 – MEMORY, NDB 支持
BITMAP 索引 – MySQL 不支持
FULLTEXT 索引 – MyISAM, Innodb(MySQL 5.6以上支持)
有不少不一樣的實現
在可加速的操做中共享相同的屬性
內存相比硬盤使生活變得美好
B+樹一般用於硬盤存儲
數據存儲於葉子節點
MyISAM
數據指針指向數據文件中的物理位置
全部索引都是同樣的(指向物理位置))
Innodb
主鍵索引 (顯式或隱式) - 直接將數據存儲於索引的葉子節點,而不是指針
二級索引 – 保存主鍵索引的值做爲數據指針
查詢全部 KEY=5 的記錄 (點查詢)
查詢全部 KEY>5 的記錄 (開合間)
查詢全部 5<KEY<10 的記錄 (閉合間)
不適用於:查詢KEY最後一個數字等於0的全部記錄
由於這不能定義爲範圍查詢操做
這(和數值)沒什麼區別… 真的
collation是爲字符串定義的排序規則
如: 「AAAA」 < 「AAAB」
前綴LIKE 查詢是一種特殊的範圍查詢
LIKE 「ABC%」 的意思是:
「ABC[最小值]」<KEY<「ABC[最大值]」
LIKE 「%ABC」 沒法使用索引查詢
是這樣進行排序的, 比較首列,而後第二列,第三列以此類推,如:
KEY(col1,col2,col3)
(1,2,3) < (1,3,1)
使用一個BTREE索引,而不是每一個層級一個單獨的BTREE索引
索引是昂貴的,不要添加多餘的索引
多數狀況下,擴展索引比添加一個新的索引要好
寫 - 更新索引經常是數據庫寫操做的主要開銷
讀 - 須要再硬盤和內存開銷空間; 查詢優化中須要額外的開銷
長主鍵索引(Innodb) – 使全部相應的二級索引 變得更長、更慢
「隨機」主鍵索引(Innodb) – 插入致使大量的頁面分割
越長的索引一般越慢
Index with insertion in random order – SHA1(‘password’)
低區分度的索引是低劣的 – 在性別字段建的索引
相關索引是不太昂貴的– insert_time與自增id是相關的
數據按主鍵彙集
選擇最佳的字段做爲主鍵
好比評論表 – (POST_ID,COMMENT_ID) 是做爲主鍵的不錯選擇,使得單個post的評論聚在一塊兒
或者 「打包」 單個 BIGINT(字段)
主鍵隱式地附加到全部索引中
KEY (A) 實質上是 KEY (A,ID)
覆蓋索引,有利於排序
查詢
排序
避免讀取數據(只讀取索引)
其餘專門的優化
SELECT * FROM EMPLOYEES WHERELAST_NAME=「Smith」
這是典型的索引 KEY(LAST_NAME)
可使用複合索引
SELECT * FROM EMPLOYEES WHERELAST_NAME=「Smith」 AND DEPT=「Accounting」
將會使用索引 KEY(DEPT,LAST_NAME)
Index (A,B,C) - 字段順序問題
下列情形將會使用索引進行查詢(全條件)
A>5
A=5 AND B>6
A=5 AND B=6 AND C=7
A=5 AND B IN (2,3) AND C>5
下列條件將不會使用索引
B>5 – 條件沒有B字段前的A
B=6 AND C=7 - 條件沒有B、C字段前的A
如下情形使用索引的一部分
A>5 AND B=2 - 第一個字段A的範圍查詢,致使只用上了索引中A字段的部分
A=5 AND B>6 AND C=2 - B字段的範圍範圍查詢,致使只使用了索引中A和B兩個字段的部分
在複合索引中,MySQL在遇到返回查詢(<,>,BETWEEN)時,將中止停止剩餘部分(索引)的使用;可是使用IN(…)的"範圍查詢"則能夠繼續往右使用索引(的更多部分)
SELECT * FROM PLAYERS ORDER BY SCOREDESC LIMIT 10
將使用索引 KEY(SCORE)
不使用索引將進行很是昂貴的「filesort」操做(externalsort)
經常使用組合索引進行查詢
SELECT * FROM PLAYERS WHERE COUNTRY=「US」ORDER BY SCORE DESC LIMIT 10
最佳選擇是 KEY(COUNTRY,SCORE)
變得更加受限!
KEY(A,B)
如下情形將會使用索引進行排序
ORDER BY A - 對索引首字段進行排序
A=5 ORDER BY B - 對第一個字段進行點查詢,對第二個字段進行排序
ORDER BY A DESC, B DESC - 對兩個字段進行相同的順序進行排序
A>5 ORDER BY A - 對首字段進行範圍查詢,並對首字段進行排序
如下情形將不使用索引進行排序
ORDER BY B - 對第二個字段進行排序(未使用首字段)
A>5 ORDER BY B – 對首字段進行範圍查詢,對第二個字段進行排序
A IN(1,2) ORDER BY B - 對首字段進行IN查詢,對第二個字段進行排序
ORDER BY A ASC, B DESC - 對兩個字段進行不一樣順序的排序
不能對兩個字段進行不一樣順序的排序
對非ORDER BY部分的字段只能使用點查詢(=)– 在這種情形下,IN()也不行
「覆蓋索引」– 這裏指 適用於特定查詢的索引,而不是一種索引的類型
只讀取索引,而不去讀取數據
SELECT STATUS FROM ORDERS WHERECUSTOMER_ID=123
KEY(CUSTOMER_ID,STATUS)
索引一般比數據自己要小
(索引)讀取起來更有次序– 讀取數據指針一般是隨機的
索引能夠幫助優化 MIN()/MAX() 這類的統計函數– 但只包含如下這些:
SELECT MAX(ID) FROM TBL;
SELECT MAX(SALARY) FROM EMPLOYEEGROUP BY DEPT_ID
將受益於 KEY(DEPT_ID,SALARY)
「Using index for group-by」
MySQL 使用 「嵌套循環(Nested Loops)」進行聯表查詢
SELECT * FROM POSTS,COMMENTS WHEREAUTHOR=「Peter」 AND COMMENTS.POST_ID=POSTS.ID
掃描表POSTS查詢全部複合條件的 posts
循環posts 在表COMMENTS 中查找 每一個post的全部comments
使每一個關聯的表(關聯字段)都使用上索引顯得很是的重要
索引只有在被查詢的字段上是必要的– POSTS.ID字段的索引再本次查詢中是用不上的
從新設計不能很好的全部索引的聯合查詢吧
MySQL可使用超過1個索引
「索引合併」
SELECT * FROM TBL WHERE A=5 AND B=6– 能夠分別使用索引 KEY(A)和 KEY(B)
索引 KEY(A,B) 是更好的選擇
SELECT * FROM TBL WHERE A=5 OR B=6– 兩個索引同時分別被使用
索引 KEY(A,B) 在這個查詢中沒法使用
你能夠在字段最左前綴創建索引
ALTER TABLE TITLE ADD KEY(TITLE(20));
須要對BLOB/TEXT類型的字段創建索引
能顯著的減小空間使用
不能用於覆蓋索引
選擇前綴長度成爲一個問題
前綴應該有足夠的區分度
比較distinct前綴、distinct整個字段的值
mysql> select count(distinct(title)) total,count(distinct(left(title,10))) p10,count(distinct(left(title,20))) p20 from title;
total | p10 | p20 |
---|---|---|
998335 | 624949 | 960894 |
1 row in set (44.19 sec)
檢查異常值
確保不會有不少記錄使用相同的前綴
使用最多的Titlemysql> select count(*) cnt, title tl from title group by tl order by cnt desc limit 3;
cnt | tl |
---|---|
136 | The Wedding |
129 | Lost and Found |
112 | Horror Marathon |
3 rows in set (27.49 sec)
使用最多的Title 前綴 mysql> select count(*) cnt, left(title,20) tl from title group by tl order by cnt desc limit 3;
cnt | tl |
---|---|
184 | Wetten, dass..? aus |
136 | The Wedding |
129 | Lost and Found |
3 rows in set (33.23 sec)
每次查詢動態選擇– 查詢文本中常量很重要
評估須要查詢的行數 對給定的索引,在表中進行"dive"
若是(dive)不可行時,使用 「Cardinality」 進行統計– 這是進行 ANALYZE TABLE時 更新的
並不僅是最小化掃描行數
不少其餘的heuristics(嘗試) and hacks– 對Innodb來講主鍵是很重要的
覆蓋索引效益
Full table scan is faster, all being equal(這句不是太明白)
咱們也可使用索引進行排序
須知
驗證MYSQL實際使用的執行計劃
注意是能夠根據常量和數據動態改變的
EXPLAIN 是一個很好的工具,能夠看到MYSQL將如何進行查詢
記住,真實的查詢可能跟執行計劃不一樣
mysql> explain select max(season_nr) from title group by production_year;
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
---|---|---|---|---|---|---|---|---|---|
1 | SIMPLE | title | range | NULL | production_year | 5 | NULL | 201 | Using index for group-by |
1 row in set (0.01 sec)
「type」 從好到差排序以下:– system,const,eq_ref,ref,range,index,ALL
注意 「rows」 – 更大的數值意味着更慢的查詢
檢查 「key_len」 – 顯示索引的哪些部分真實使用到了
留意"Extra"
Using Index - 好
Using Filesort, Using Temporary - 差
爲你的關鍵性能查詢集創建索引– 總體取審視他們,而不是一個個看
最好全部的查詢條件和聯表條件都使用索引– 起碼區分度最高的部分是
通常來講,能夠的話,擴展索引,而不是建立新的索引
修改時記得驗證對性能的影響
按能支持更多查詢的順序創建索引
SELECT * FROM TBL WHERE A=5 AND B=6
SELECT * FROM TBL WHERE A>5 AND B=6– 對兩個查詢來講 KEY(B,A) 是更好的選擇
把全部都是點查詢的字段放到索引的首位
不要添加非性能關鍵查詢的索引– 太多的索引會使MYSQL慢下來
KEY (A,B)
SELECT * FROM TBL WHERE A BETWEEN 2AND 4 AND B=5
將只使用索引的第一個字段部分
SELECT * FROM TBL WHERE A IN (2,3,4) ANDB=5
索引的兩個字段部分都使用
KEY (GENDER,CITY)
SELECT * FROM PEOPLE WHERE CITY=「NEWYORK」
徹底用不上索引
SELECT * FROM PEOPLE WHERE GENDER IN(「M」,」F」) AND CITY=「NEW YORK」
將用上索引
這個Trick在低區別度的字段上能夠很好的使用
Gender, Status, Boolean Types etc
KEY(A,B)
SELECT * FROM TBL WHERE A IN (1,2) ORDER BYB LIMIT 5;
沒法使用索引進行排序
(SELECT FROM TBL WHERE A=1 ORDER BY B LIMIT 5) UNION ALL (SELECT FROM TBL WHERE A=2 ORDER BY B LIMIT 5) ORDER BY B LIMIT 5;
將會用上索引,而「filesort」只用於對不超過10行記錄