mysql索引背后的数据_MySQL索引背后的数据结构及算法原理(4)

本文详细介绍了MySQL索引在不同查询条件下的使用情况,包括精确匹配、范围查询、前缀匹配等。通过实例分析,解释了如何通过调整查询条件和创建辅助索引来提高查询效率。此外,还提到了'填坑'优化方法,即在索引列值较少的情况下,使用IN操作符提高索引利用率。最后,强调了正确理解和区分多值匹配与范围查询的重要性,以避免对MySQL行为产生误解。
摘要由CSDN通过智能技术生成

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

+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+

| 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

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的行为产生困惑。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值