近日整理文檔時發現多年前的這個文檔仍是蠻實用的,而後在網絡搜索了一下並無相關的譯文,因此決定把它翻譯過來,若有不當的地方請多包涵和指正。原文地址:https://www.percona.com/files...html
如下是譯文:mysql
理解索引對開發和dba來講都是極其重要web
差勁的索引對產品問題負至關大的一部分責任sql
索引不是多麼高深的問題數據庫
理解索引網絡
爲你的應用建立最佳索引dom
擁抱MySQL的限制函數
索引有什麼用工具
爲從數據庫讀取數據加速oop
強制約束 (惟一索引 UNIQUE, 外鍵 FOREIGN KEY)
沒有任何索引的狀況下查詢頁能正常運行
可是那可能須要執行很長的時間
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 WHERE
LAST_NAME=「Smith」
這是典型的索引 KEY(LAST_NAME)
可使用複合索引
SELECT * FROM EMPLOYEES WHERE
LAST_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 SCORE
DESC LIMIT 10
將使用索引 KEY(SCORE)
不使用索引將進行很是昂貴的「filesort」操做(external
sort)
經常使用組合索引進行查詢
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 WHERE
CUSTOMER_ID=123
KEY(CUSTOMER_ID,STATUS)
索引一般比數據自己要小
(索引)讀取起來更有次序
– 讀取數據指針一般是隨機的
索引能夠幫助優化 MIN()/MAX() 這類的統計函數
– 但只包含如下這些:
SELECT MAX(ID) FROM TBL;
SELECT MAX(SALARY) FROM EMPLOYEE
GROUP BY DEPT_ID
將受益於 KEY(DEPT_ID,SALARY)
「Using index for group-by」
MySQL 使用 「嵌套循環(Nested Loops)」進行聯表查詢
SELECT * FROM POSTS,COMMENTS WHERE
AUTHOR=「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)
檢查異常值
確保不會有不少記錄使用相同的前綴
使用最多的Title
mysql> 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 2
AND 4 AND B=5
將只使用索引的第一個字段部分
SELECT * FROM TBL WHERE A IN (2,3,4) AND
B=5
索引的兩個字段部分都使用
KEY (GENDER,CITY)
SELECT * FROM PEOPLE WHERE CITY=「NEW
YORK」
徹底用不上索引
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 BY
B 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行記錄
做者的ppt發出來後,不少人向他諮詢相關問題,另外專門作了回覆,oschina已經有對回覆進行了翻譯:
http://www.oschina.net/transl...