错误使用索引引起的性能问题

索引真的不一定更快

1. 原查询代码,以及索引信息

SELECT
    sourceId,
    group_concat( DISTINCT targetId ORDER BY created DESC ) targetIds,
    max( created ) lastTime 
FROM
    message_table 
WHERE
	( created >= '2018-10-12 08:00:00' AND created <= '2018-10-12 10:59:59' ) 
GROUP BY sourceId)
索引索引列
idxSourceIdsourceId(Int)
idxTargetIdstargetId(Int)
idxSourceTargetsourceId, targetId

执行查询,花费了170s(这是多次测试后,最低的一次)

2. 那好吧,只有explain一下了

+----+-------------+------------------+------------+-------+----------------------------+-----------+---------+------+---------+----------+-------------+
| id | select_type | table            | partitions | type  | possible_keys              | key       | key_len | ref  | rows    | filtered | Extra       |
+----+-------------+------------------+------------+-------+----------------------------+-----------+---------+------+---------+----------+-------------+
|  1 | SIMPLE      | message_table | NULL       | index | idxSourceTarget,idxSourceId | idxSourceId | 4       | NULL | 9783185 |    11.11 | Using where |
+----+-------------+------------------+------------+-------+----------------------------+-----------+---------+------+---------+----------+-------------+

看一下,大致看一下,居然扫描了全部的数据,而且还是在使用了索引的情况下。等一下,为什么要使用idxSourceId这个索引,根本没有减少需要扫描的行数啊

3. 强制不使用索引

......
FROM
    message_table ignore index(idxSourceTarget,idxSourceId) 
......

执行查询,花费了10s,哈哈,不使用索引之后居然降低到了10s,但是仍然不行,线上大概有1.2亿条数据,而且在不断增多(性能问题,也是因为数据不断增多才出现的)

4. 好吧,把created字段加上索引试一试

注:ignore index(idxSourceTarget,idxSourceId)

ALTER TABLE `message_table` 
ADD INDEX `idxCreated`(`created`);

执行查询,0.772s

5. 高兴的太早了

将时间范围加大,大到一个时间范围内有100万条数据的情况

WHERE created >= '2010-10-12 08:00:00' AND created <= '2019-01-05 10:59:59'

执行查询,4s

6. 使用覆盖索引

ALTER TABLE `message_table` 
DROP INDEX `idxCreated`,
ADD INDEX `idxCreated`(`created`, `sourceId`, `targetId`) USING BTREE;

执行查询,0.984s,呦西,今天加个鸡腿

7. 更多优化

  1. 优化分组后的排序
    group_concat( DISTINCT targetId ORDER BY created DESC ) targetIds

这个优化可以看出来,每个GROUP BY里面都需要进行排序,那为什么不一次性完成排序呢

SELECT
    table_tmp.sourceId,
    group_concat(DISTINCT table_tmp.targetId ) targetIds,
    max( table_tmp.created ) lastTime 
FROM
    (SELECT sourceId, targetId, created 
		FROM message_table 
		WHERE created >= '2010-10-12 08:00:00' AND created <= '2019-01-05 10:59:59' 
		ORDER BY created) 
		AS table_tmp
GROUP BY table_tmp.sourceId 

执行查询:0.679s,算是更进一步

  1. 优化时间索引
    因为我们的查询大多是会查询比较新的数据,所以如果索引能够是倒序索引,那么就能够更快的定位到数据,目前MYSQL8.0以上是支持的
    倒序索引

总结

  1. 使用idxSource索引,引起的性能问题,因为GROUP BY分组字段上有索引,时间(created)字段没有索引,这个时候mysql会使用分组字段的索引来查找分组数据
  2. 使用覆盖索引,减少对磁盘的随机访问

我的个人博客,有空来坐坐

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值