目的sql
數據庫中很重要的設計一部分,莫過於索引了。B+樹索引是MySQL中設計的索引。B+樹索引是基於B+樹基礎發展而來的。數據庫
前面文章MySQL 索引選擇原則分析(一)已經對索引作進一步分析。可是實踐比較少,只是根據理論作了部分分析,下面對MySQL本身推出的測試數據庫及數據作一些SQL的分析。函數
MySQL示例庫下載:測試
http://pan.baidu.com/s/1ntxmgXV優化
一:全列匹配
spa
SELECT * FROM titles WHERE emp_no='10001' AND title='Senior Engineer' AND from_date='1986-06-26'; SELECT * FROM titles WHERE from_date='1986-06-26' AND emp_no='10001' AND title='Senior Engineer';
當按照索引中全部列進行精確匹配("="或"IN")時,索引能夠被用到。注:理論上索引對順序是敏感的,可是因爲MySQL的查詢優化器會自動調整where語句的條件順序以使用適合的索引,所以前面2條SQL的查詢計劃是同樣的。
.net
二:最左前綴匹配
設計
SELECT * FROM titles WHERE emp_no='10001';
SQL查詢計劃能夠看出,key用的是PRIMARY索引,可是key_len爲4,說明只用了索引第一列。當查詢條件精確匹配索引的左邊連續一個或幾個列時,如<emp_no>或<emp_no,title,from_date>,因此能夠被用到,可是隻能用到一部分,即where條件所組成的最左前綴。
code
三:查詢條件用到了索引中列的精確匹配,可是中間某個條件未提供
orm
SELECT * FROM titles WHERE emp_no='10001' AND from_date='1986-06-26';
此時查詢計劃與(二)相同,由於title未提供,因此查詢只用到了索引的第一列,而from_date雖然也在索引中,可是因爲title不存在而沒法和左前綴鏈接,所以須要對結果進行掃描過濾from_date。
四:查詢條件沒有指定索引第一列
SELECT * FROM titles WHERE title='Senior Engineer'; SELECT * FROM titles WHERE from_date='1986-06-26';
因爲不是最左前綴,因此查詢計劃使用的是全表掃描。
五:匹配某列的前綴字符串
SELECT * FROM titles WHERE emp_no='10001' AND title LIKE 'Senior%'; SELECT * FROM titles WHERE emp_no='10001' AND title LIKE '%Senior%';
根據查詢計劃第一句SQL,type是range,key_len爲156,使用了索引的第一列及第二列。
第二劇SQL,查詢計劃與(二)相同,也就使用了索引的第一列。因此LIKE時候也能夠根據具體狀況來進行優化的。
六:範圍查詢
SELECT * FROM titles WHERE emp_no < '10010' AND title='Senior Engineer'; SELECT * FROM titles WHERE emp_no < '10010' AND title='Senior Engineer' AND from_date BETWEEN '1986-01-01' AND '1986-12-31'; SELECT * FROM titles WHERE emp_no IN ('10001','10002','10003','10004','10005','10006','10007','10008', '10009') AND title='Senior Engineer' AND from_date BETWEEN '1986-01-01' AND '1986-12-31'; SELECT * FROM titles WHERE emp_no BETWEEN '10000' AND '10009' AND title='Senior Engineer' AND from_date BETWEEN '1986-01-01' AND '1986-12-31';
第一句SQL查詢計劃,type爲range,key_len爲4,使用了索引的第一列。第二句SQL查詢計劃,能夠看出與第一句是同樣的。所以能夠看出,範圍列能夠用到索引,可是範圍列後面的列沒法用到索引。
第三句SQL查詢計劃,type爲range,key_len爲159,也就是使用了索引的全部列。IN使用的是值匹配。
第四句SQL查詢計劃,type爲range,key_len爲159,也就是使用了索引的全部列。因此做用於emp_no上的"BETWEEN"實際上至關於"IN",也就是值匹配。
MySQL的查詢計劃根據type能夠沒法區分範圍索引和多值匹配,由於都是range。所以三、4句SQL纔會都用到索引的全部列。
七:查詢條件中含有函數或表達式
SELECT * FROM titles WHERE emp_no='10001' AND LEFT(title, 6)='Senior'; SELECT * FROM titles WHERE emp_no - 1='10000'; SELECT * FROM titles WHERE emp_no=10000 + 1;
第一句SQL查看查詢計劃,發現key_len爲4,也就是使用了索引中的第一列。所以查詢條件中包含函數或表達式,則MySQL不會爲這列使用索引。
第二句SQL查看查詢計劃,type爲ALL,也就是全表掃描,MySQL沒有使用索引,MySQL的優化器沒有自動的優化常量表達式。
第三句SQL查看查詢計劃,明顯使用了索引的第一列,所以編寫SQL時,常量計算儘可能放到右邊,左邊儘可能少用表達式。