0

0

MySQL一个异常查询问题追查_MySQL

php中文网

php中文网

发布时间:2016-06-01 13:14:00

|

985人浏览过

|

来源于php中文网

原创

问题

线上碰到的问题:相同的语句,只是最后的limit行数不同。奇怪的是,limit 10 的性能比limit 100的语句还慢约10倍。隐藏用户表信息,语句及结果如下SELECTf1 , SUM(`f2`) `CNT` FROM TWHERE f1 IS NOT NULL AND f3 = '2014-05-12' GROUP BY f1 ORDER BY `CNT` DESC LIMIT 10;执行时间3 min 3.65 secSELECTf1 , SUM(`f2`) `CNT` FROM TWHERE f1 IS NOT NULL AND f3 = '2014-05-12' GROUP BY f1 ORDER BY `CNT` DESC LIMIT 100;执行时间1.24Sec.性能差距非常大!

分析

MySQL Tips:追查语句执行时最常用的方法,是通过explain来看语句的执行计划。 
更有冲击性的效果是通过缩小范围后,在这个数据下,limit 67和limit 68的执行计划相差很大。两个执行计划:LIMIT 67 id: 1select_type: SIMPLEtable: atype: rangepossible_keys: A,B,Ckey: Bkey_len: 387ref: NULLrows: 2555192Extra: Using where; Using temporary; Using filesort1 row in set (0.00 sec) LIMIT 68id: 1select_type: SIMPLEtable: atype: refpossible_keys: A,B,Ckey: Akey_len: 3ref: constrows: 67586Extra: Using where; Using temporary; Using filesort1 row in set (0.00 sec)可以看到,两个语句的执行计划不同:使用的索引不同。
MySQL Tips:explain的结果中,key表示最终使用的索引,rows表示使用这个索引需要扫描的行数,这是个估计值。表中 索引A定义为 (f3, f4, f1, f2, f5); 索引B定义为(f1, f2, f3);

一个确认

虽然rows是估计值,但是指导索引使用的依据。既然limit 68能达到rows 67586, 说明在第一个语句优化器可选结果中,也应该有此值,为什么不会选择索引A?先确认一下我们上面的这个结论。
MySQL Tips:MySQL语法中能够用force index 来强行要求优化器使用某一个索引。

Explain SELECT f1 , SUM(f2CNT FROM t force index(A) WHERE f1 IS NOT NULL AND f3 = ‘2014-05-12’ GROUP BY P ORDER BY CNT DESC LIMIT 67/G

id: 1 
select_type: SIMPLE 
table: a 
type: ref 
possible_keys:A 
key: A 
key_len: 3 
ref: const 
rows: 67586 
Extra: Using where; Using temporary; Using filesort 
1 row in set (0.00 sec)

顺便说明,由于我们指定了force index,因此优化器不会考虑其他索引,possible_keys里只会显示A。我们关注的是rows:67586。这说明在limit 67语句里,使用索引A也能够减少行扫描。
MySQL Tips:MySQL优化器会对possiable_key中的每个可能索引都计算查询代价,选择最小代价的查询计划。
至此我们大概可以猜测,这个应该是MySQL实现上的bug:没有选择合适的索引,导致使用了明显错误的执行计划。
MySQL Tips:MySQL的优化器执行期间需要依赖于表的统计信息,而统计信息是估算值,因此有可能导致得到的执行计划非最优。
但要说明的是,上述Tip是客观情况造成(可接受),但本例却是例外,因此优化器实际上可以拿到能够作出选择正确结果的数据(rows值),但是最终选择错误。

原因分析

灵办AI
灵办AI

免费一键快速抠图,支持下载高清图片

下载
MySQL优化器是按照查询代价的估算值,来确定要使用的索引。计算这个估算值的过程,基本是按照“估计需要扫描的行数”来确定的。
MySQL Tips:MySQL在目前集团主流使用的5.1和5.5版本中只能使用前缀索引。

因此,使用索引A只能用上字段f3,使用索引B只能用上字段f1。Rows即为使用了索引查到上下界,之后需要扫描的数据行数(估算值)。

上述的语句需要用到group和order by,因此执行计划中都有Using temporary; Using filesort。流程上按顺序先计算使用索引A的查询代价。之后依次计算其他possitabe_key的查询代价。由于过程中需要排序,在得到一个暂定结果后,需要判断是否有代价更低的排序方式(test_if_cheaper_ordering)。与之前的大同小异,也是依靠估计扫描行数来计算代价。在这个逻辑的实现过程中,存在一个bug:在估计当前索引的区分度的时候,没有考虑到前缀索引。即:假设表中有50w行数据,索引B(f1,f2,f3),则计算索引区分度时,需要根据能够用上的前缀部分来确定。比如f1有1000个不同的值,则平均每个key值上的记录数为500.如(f1,f2)有10000个同的值,则平均每个组合key上的记录数为50,若(f1,f2,f3)有50w个不同的值,则平均每个组合key上的记录数为1。
MySQL Tips:每个key上的记录数越少,说明使用该索引查询时效率最高。对应于show index from tbl 输出结果中的Cardinality值越大。

在这个case下,索引A只能使用f1做前缀索引,但是在计算单key上的行平均值时用的是(f1,f2,f3),这就导致估算用索引B估算的时候,得到的代价偏小。导致误选。

回到问题本身

1、为什么limit值大的时候反而选对了呢?
2、这个表有50w行数就,为什么limit相差为就差别这么大?这与语句本身有关。这个语句中有group by,这就意味着每多limit一个值,实际上需要扫描更多的行N。 这里N为“表的总行数”/“表中不同的f2值”。也就是说这个语句使得这个bug有放大作用。

解决方案

分析清楚后解决方法就比较简单了,修改代码逻辑,在执行test_if_cheaper_ordering过程中,改用字段f1的区分度来计算即可。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法
pixiv网页版官网登录与阅读指南_pixiv官网直达入口与在线访问方法

本专题系统整理pixiv网页版官网入口及登录访问方式,涵盖官网登录页面直达路径、在线阅读入口及快速进入方法说明,帮助用户高效找到pixiv官方网站,实现便捷、安全的网页端浏览与账号登录体验。

286

2026.02.13

微博网页版主页入口与登录指南_官方网页端快速访问方法
微博网页版主页入口与登录指南_官方网页端快速访问方法

本专题系统整理微博网页版官方入口及网页端登录方式,涵盖首页直达地址、账号登录流程与常见访问问题说明,帮助用户快速找到微博官网主页,实现便捷、安全的网页端登录与内容浏览体验。

126

2026.02.13

Flutter跨平台开发与状态管理实战
Flutter跨平台开发与状态管理实战

本专题围绕Flutter框架展开,系统讲解跨平台UI构建原理与状态管理方案。内容涵盖Widget生命周期、路由管理、Provider与Bloc状态管理模式、网络请求封装及性能优化技巧。通过实战项目演示,帮助开发者构建流畅、可维护的跨平台移动应用。

42

2026.02.13

TypeScript工程化开发与Vite构建优化实践
TypeScript工程化开发与Vite构建优化实践

本专题面向前端开发者,深入讲解 TypeScript 类型系统与大型项目结构设计方法,并结合 Vite 构建工具优化前端工程化流程。内容包括模块化设计、类型声明管理、代码分割、热更新原理以及构建性能调优。通过完整项目示例,帮助开发者提升代码可维护性与开发效率。

19

2026.02.13

Redis高可用架构与分布式缓存实战
Redis高可用架构与分布式缓存实战

本专题围绕 Redis 在高并发系统中的应用展开,系统讲解主从复制、哨兵机制、Cluster 集群模式及数据分片原理。内容涵盖缓存穿透与雪崩解决方案、分布式锁实现、热点数据优化及持久化策略。通过真实业务场景演示,帮助开发者构建高可用、可扩展的分布式缓存系统。

23

2026.02.13

c语言 数据类型
c语言 数据类型

本专题整合了c语言数据类型相关内容,阅读专题下面的文章了解更多详细内容。

29

2026.02.12

雨课堂网页版登录入口与使用指南_官方在线教学平台访问方法
雨课堂网页版登录入口与使用指南_官方在线教学平台访问方法

本专题系统整理雨课堂网页版官方入口及在线登录方式,涵盖账号登录流程、官方直连入口及平台访问方法说明,帮助师生用户快速进入雨课堂在线教学平台,实现便捷、高效的课程学习与教学管理体验。

14

2026.02.12

豆包AI网页版入口与智能创作指南_官方在线写作与图片生成使用方法
豆包AI网页版入口与智能创作指南_官方在线写作与图片生成使用方法

本专题汇总豆包AI官方网页版入口及在线使用方式,涵盖智能写作工具、图片生成体验入口和官网登录方法,帮助用户快速直达豆包AI平台,高效完成文本创作与AI生图任务,实现便捷智能创作体验。

421

2026.02.12

PostgreSQL性能优化与索引调优实战
PostgreSQL性能优化与索引调优实战

本专题面向后端开发与数据库工程师,深入讲解 PostgreSQL 查询优化原理与索引机制。内容包括执行计划分析、常见索引类型对比、慢查询优化策略、事务隔离级别以及高并发场景下的性能调优技巧。通过实战案例解析,帮助开发者提升数据库响应速度与系统稳定性。

51

2026.02.12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
SciPy 教程
SciPy 教程

共10课时 | 1.6万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号