MySQL索引背后的数据结构及算法原理(4)
MySQL索引背后的数据结构及算法原理(4)
情况三:查询条件用到了索引中列的精确匹配,但是中间某个条件未提供。
view sourceprint?EXPLAIN SELECT * FROM employees.titles WHERE emp_no='10001' AND from_date='1986-06-26';
EXPLAIN SELECT*FROM employees.titles WHERE emp_no='10001'AND from_date='1986-06-26';
+----+-------------+--------+------+---------------+---------+---------+-------+------+-------------+
| id | select_type |table| type | possible_keys |key| key_len | ref | rows | Extra |
+----+-------------+--------+------+---------------+---------+---------+-------+------+-------------+
|1| SIMPLE | titles | ref |PRIMARY|PRIMARY|4| const |1| Using where|
+----+-------------+--------+------+---------------+---------+---------+-------+------+-------------+
此时索引使用情况和情况二相同,因为title未提供,所以查询只用到了索引的第一列,而后面的from_date虽然也在索引中,但是由于title不存在而无法和左前缀连接,因此需要对结果进行扫描过滤from_date(这里由于emp_no唯一,所以不存在扫描)。如果想让from_date也使用索引而不是where过滤,可以增加一个辅助索引,此时上面的查询会使用这个索引。除此之外,还可以使用一种称之为“隔离列”的优化方法,将emp_no与from_date之间的“坑”填上。
首先我们看下title一共有几种不同的值:
SELECTDISTINCT(title) FROM employees.titles;
+--------------------+
| title |
+--------------------+
| Senior Engineer |
| Staff |
| Engineer |
| Senior Staff |
| Assistant Engineer |
| Technique Leader |
| Manager |
+--------------------+
只有7种。在这种成为“坑”的列值比较少的情况下,可以考虑用“IN”来填补这个“坑”从而形成最左前缀:
EXPLAIN SELECT*FROM employees.titles
WHERE emp_no='10001'
AND title IN ('Senior Engineer', 'Staff', 'Engineer', 'Senior Staff', 'Assistant Engineer', 'Technique Leader', 'Manager')
AND from_date='1986-06-26';
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type |table| type | possible_keys |key| key_len | ref | rows | Extra |
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+
|1| SIMPLE | titles | range |PRIMARY|PRIMARY|59|NULL|7| Using where|
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+
这次key_len为59,说明索引被用全了,但是从type和rows看出IN实际上执行了一个range查询,这里检查了7个key。看下两种查询的性能比较:
“填坑”后性能提升了一点。如果经过emp_no筛选后余下很多数据,则后者性能优势会更加明显。当然,如果title的值很多,用填坑就不合适了,必须建立辅助索引。
情况四:查询条件没有指定索引第一列。
Query_ID | Duration | Query +----------+------------+-------------------------------------------------------------------------------+
|10|0.00058000|SELECT*FROM employees.titles WHERE emp_no='10001'AND from_date='1986-06-26'|
|11|0.00052500|SELECT*FROM employees.titles WHERE emp_no='10001'AND title IN ... |
+----------+------------+-------------------------------------------------------------------------------+
由于不是最左前缀,索引这样的查询显然用不到索引。
情况五:匹配某列的前缀字符串。
EXPLAIN SELECT*FROM employees.titles WHERE emp_no='10001'AND title LIKE'Senior%';
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type |table| type | possible_keys |key| key_len | ref | rows | Extra |
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+
|1| SIMPLE | titles | range |PRIMARY|PRIMARY|56|NULL|1| Using where|
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+
此时可以用到索引,但是如果通配符不是只出现在末尾,则无法使用索引。
情况六:范围查询。
view sourceprint?EXPLAIN SELECT * FROM employees.titles WHERE emp_no<'10010' and title='Senior Engineer';
EXPLAIN SELECT*FROM employees.titles WHERE emp_no<'10010'and title='Senior Engineer';
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type |table| type | possible_keys |key| key_len | ref | rows | Extra |
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+
|1| SIMPLE | titles | range |PRIMARY|PRIMARY|4|NULL|16| Using where|
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+
范围列可以用到索引(必须是最左前缀),但是范围列后面的列无法用到索引。同时,索引最多用于一个范围列,因此如果查询条件中有两个范围列则无法全用到索引。
可以看到索引对第二个范围索引无能为力。这里特别要说明MySQL一个有意思的地方,那就是仅用explain可能无法区分范围索引和多值匹配,因为在type中这两者都显示为range。同时,用了“between”并不意味着就是范围查询,例如下面的查询:
EXPLAIN SELECT*FROM employees.titles
WHERE emp_no<'10010'
AND title='Senior Engineer'
AND from_date BETWEEN'1986-01-01'AND'1986-12-31';
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+
| id | select_type |table| type | possible_keys |key| key_len | ref | rows | Extra |
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+
|1| SIMPLE | titles | range |PRIMARY|PRIMARY|4|NULL|16| Using where|
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+
看起来是用了两个范围查询,但作用于emp_no上的“BETWEEN”实际上相当于“IN”,也就是说emp_no实际是多值精确匹配。可以看到这个查询用到了索引全部三个列。因此在MySQL中要谨慎地区分多值匹配和范围匹配,否则会对MySQL的行为产生困惑。
分享到:
相关推荐
MySQL索引背后的数据结构及算法原理,深入了解mysql的索引实现原理
MySQL索引背后的数据结构及算法原理,帮助了解MYsql的索引和原理,高级工程师进阶的必选。。。。。
MySQL索引背后的数据结构及算法原理.pdfMySQL索引背后的数据结构及算法原理.pdfMySQL索引背后的数据结构及算法原理.pdfMySQL索引背后的数据结构及算法原理.pdfMySQL索引背后的数据结构及算法原理.pdfMySQL索引背后的...
MySQL索引背后的数据结构及算法原理.docxMySQL索引背后的数据结构及算法原理.docxMySQL索引背后的数据结构及算法原理.docxMySQL索引背后的数据结构及算法原理.docxMySQL索引背后的数据结构及算法原理.docxMySQL索引...
MySQL索引背后的数据结构及算法原理[整理].pdf
CodingLabs - MySQL索引背后的数据结构及算法原理_files.7z
不过要是想知道的多一点,想研究一下如何优化数据库,那么一定避免不了研究索引的原理,如果想要真正明白索引是怎么工作的,如何合理的使用索引以优化数据库,那么就免不了纠结于一堆数据结构与算法之间了。...
本文以MySQL数据库为研究对象,讨论与数据库索引相关的...特别需要说明的是,MySQL支持诸多存储引擎,而各种存储引擎对索引的支持也各不相同,因此MySQL数据库支持多种索引类型,如BTree索引,哈希索引,全文索引等等
MySql的主从实时备份同步的配置,以及原理(从库读主库的binlog),读写分离 Mysql主从同步的实现原理 MySQL索引背后的数据结构及算法原理 摘要数据结构及算法基础 索引的本质 B-Tree和B+Tree B-Tree B+Tree 带有顺序...
MySql的主从实时备份同步的配置,以及原理(从库读主库的binlog),读写分离 Mysql主从同步的实现原理 MySQL索引背后的数据结构及算法原理 摘要数据结构及算法基础 索引的本质 B-Tree和B+Tree B-Tree B+Tree 带有顺序...
MySql的主从实时备份同步的配置,以及原理(从库读主库的binlog),读写分离 Mysql主从同步的实现原理 MySQL索引背后的数据结构及算法原理 摘要数据结构及算法基础 索引的本质 B-Tree和B+Tree B-Tree B+Tree 带有顺序...
MySql的主从实时备份同步的配置,以及原理(从库读主库的binlog),读写分离 Mysql主从同步的实现原理 MySQL索引背后的数据结构及算法原理 摘要数据结构及算法基础 索引的本质 B-Tree和B+Tree B-Tree B+Tree 带有顺序...