目的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时,常量计算尽可能放到右边,左边尽可能少用表达式。