MySQL 查询性能: 越复杂的 SQL 查询反而越快? 2/2

在前一篇我们分析了一个反直觉的 MySQL 查询案例,MySQL 查询性能: 越少的结果集越慢 越多的越快? 1/2 (https://ufqi.com/blog/mysql-limit-10-vs-100/ ),这一次我们继续进行另外一个 MySQL 查询的分析,无独有偶,这个看起来也很反直觉,两个对比的 SQL ,简单的看起来很慢,而复杂一些的 SQL 反而执行起来却是很快。

UfqiNews 有福新闻 中,运行日志中,偶尔很看到类似下面这样的警告信息。
mod/news: slow sql:select wordid, count(pageid) as pagecount from news_page2wordtbl where inserttime>=’2025-12-20 00:00:00′ group by wordid order by pagecount desc limit 18, return and wait…. func:[getTopXWord]…

针对这样的预警信息,优化起来却是无从下手,除了启用缓存、增加索引等常规手段外,再无良策,按照传统的思路,这个 SQL 查询已经很简单了,性能瓶颈在 group by 环节,可是业务逻辑就需要这样的数据。怎么办?

现在有了 人工智能 AI 助手,一切问题都难不倒它,所有人都应该大胆地去尝试各种不懂不会更不敢的东西。
AI 助手 宛如开了上帝视角一样,无所不能,无所不在。
下面就是通过 AI 助手 字节跳动的 豆包,针对这个 SQL 查询反直觉的解析与处理优化建议。

问题描述:
MYSQL 对比分析,两个查询意义相同,
mysql> select wordid, count(pageid) as pagecount from news_page2wordtbl where pageid in (select id from news_pagetbl where inserttime>=’2025-12-20′) and inserttime>=’2025-12-20 18:00:00′ group by wordid order by pagecount desc limit 18;
这个相对复杂查询会相对较快,几秒可以完成,
而下面这个简单的查询,却很慢,几十秒都无法返回预期结果集,
mysql> select wordid, count(pageid) as pagecount from news_page2wordtbl where inserttime>=’2025-12-20 18:00:00′ group by wordid order by pagecount desc limit 18;

看似更复杂的第一个 MySQL 查询,反而比第二个简单查询执行更快,我们来从数据过滤量级、索引生效、聚合排序开销三个核心维度拆解原因,并补充优化建议.

一、核心原因:第一个查询多了「前置数据过滤」,大幅减少后续处理量

两个查询的关键差异在于:第一个查询通过 pageid IN (子查询) 多增加了一层过滤条件,这不是 “复杂” 的负担,而是提前缩小了需要处理的数据集规模,这是它更快的根本原因。

  1. 两个查询的过滤逻辑对比
    • 第二个查询(慢):仅依靠 news_page2wordtbl 自身的 inserttime>='2025-12-20 18:00:00' 过滤,会取出这张表中该时间点之后的所有记录,无论这些 pageid 是否在 news_pagetbl 中有有效数据(即 inserttime>='2025-12-20' 的页面)。
    • 第一个查询(快):是双重过滤的交集,先通过子查询从 news_pagetbl 筛选出 2025-12-20 之后的有效 pageid,再让 news_page2wordtbl 仅匹配这些有效 pageid,同时满足自身的 inserttime 条件。
  2. 关键结论:无效记录被提前排除news_page2wordtbl 中满足 inserttime>='2025-12-20 18:00:00' 的记录里,大概率包含大量「无效 pageid」(即这些 pageid 对应的页面在 news_pagetbl 中早于 2025-12-20,无业务意义)。第一个查询通过 pageid IN (子查询) 提前剔除了这些无效记录,使得后续的 group bycountorder by 只需要处理小批量有效数据;而第二个查询需要处理大批量包含无效数据的全量结果,两者的处理开销天差地别。

二、辅助原因:索引的生效效率差异

查询速度的快慢与索引是否高效生效直接相关,两个查询的索引利用效率存在明显差距:

  1. 子查询的索引支撑(低成本高效过滤)子查询 select id from news_pagetbl where inserttime>='2025-12-20' 中,若 news_pagetblinserttime 建立了索引(推荐「覆盖索引」idx_inserttime_id (inserttime, id)),该子查询会:
    • 快速通过索引定位到 2025-12-20 之后的记录,无需全表扫描;
    • 覆盖索引直接包含 id 字段,无需回表读取全表数据,瞬间返回有效 pageid 列表,几乎无性能瓶颈。
  2. news_page2wordtbl 的索引利用差异
    • 第一个查询:过滤条件是 pageid IN (...) AND inserttime>='...',若 news_page2wordtbl 建立了联合索引(如 idx_pageid_inserttime_wordid (pageid, inserttime, wordid)),索引会同时满足两个过滤条件,直接过滤出有效数据,且索引包含 wordid,支撑后续 group by 无需额外排序。
    • 第二个查询:仅靠 inserttime>='...' 过滤,存在两个问题:① 若 inserttime 索引的选择性不高(即该时间后的数据占表总数据比例较大,比如超过 30%),MySQL 会认为索引扫描效率不如全表扫描,直接放弃索引,走全表扫描,开销暴增;② 即便 inserttime 索引生效,后续 group by wordid 仍需对大批量数据创建临时表、进行文件排序,消耗大量 CPU 和 IO 资源。

三、额外原因:聚合与排序的开销差异

group by wordidorder by pagecount desc 是查询中开销较大的操作,其开销与处理的数据量正相关:

  • 第一个查询:处理数据量小,group by 无需创建大规模临时表,order by 仅需对少量聚合结果排序,甚至可利用索引避免文件排序,开销极低;
  • 第二个查询:处理数据量大,group by 需创建大容量临时表存储聚合结果,order by 需对大量聚合结果进行文件排序(磁盘 IO 操作),这两个操作是查询变慢的 “重灾区”。

四、补充:验证方法与优化建议

  1. 验证数据量级差异(佐证核心原因)执行以下两条语句,对比返回的记录数,即可直观看到数据量差距:
    -- 子查询返回的有效pageid数量(大概率较少)
    select count(distinct id) from news_pagetbl where inserttime>='2025-12-20';
    -- 第二个查询需要处理的记录数(大概率较多)
    select count(pageid) from news_page2wordtbl where inserttime>='2025-12-20 18:00:00';
  2. 索引优化(进一步提升效率)
    • news_pagetbl:创建覆盖索引 idx_inserttime_id (inserttime, id),子查询无需回表,直接从索引获取数据;
    • news_page2wordtbl:创建联合索引 idx_pageid_inserttime_wordid (pageid, inserttime, wordid),实现 “过滤 – 聚合 – 计数” 全流程覆盖索引扫描,无需读取表数据。
  3. SQL 改写(子查询→JOIN,优化大结果集场景)当子查询返回的 pageid 较多时,IN 可能不如 INNER JOIN 高效,等价改写如下:
    select np2w.wordid, count(np2w.pageid) as pagecount from news_page2wordtbl np2w
    inner join news_pagetbl np on np2w.pageid = np.id
    where np.inserttime >= '2025-12-20' and np2w.inserttime >= '2025-12-20 18:00:00'
    group by np2w.wordid
    order by pagecount desc limit 18;

总结

  1. 第一个查询更快的核心是「pageid IN (子查询) 前置过滤」,大幅减少了后续聚合、排序的处理数据量;
  2. 索引的高效生效是辅助,避免了全表扫描和额外回表开销;
  3. 看似 “复杂” 的查询不一定慢,关键在于是否能有效缩小数据处理规模,这是 MySQL 查询优化的核心思路之一。

ufqinews logo
有福新闻 UfqiNews

这里呈现热点全局, 尺寸间一览所有令人关注的疑点焦点;
这里表达条分缕析, 视野内一睹各个脉络清晰的故事主线.
有福新闻UfqiNews 带来全新的资讯阅览体验, 不信息过载, 亦不信息茧房.

在寻求最大社会共识和满足千人千面之间谋取平衡,
在满足广泛涉猎与追求术业专攻之间谋取平衡.
媒介插上人工智能的翅膀将如虎添翼, 与资讯比翼双飞.
新闻爱好者的良心之选, 匠心之作.

UfqiNews presents the hot spots globally, with all interesting points at a glance.
Information is organized here and there is a clear storyline within every single detail.
UfqiNews brings a brand new reading experience, no information overload and no information Cocoons,

In seeking a balance of the maximum social consensus and meeting thousands of people for each interest,
In achieving a balance between satisfying a wide range of hunting and pursuing specialization in the industry.
That media is being born with wings of the artificial intelligence will be even more powerful and the information will fly swifter than ever.
Better choices of newsreaders and the art of work from them.

此条目发表在UfqiNews有福新闻, 服务器运维, 社会生活, 计算机技术分类目录,贴了, , , , 标签。将固定链接加入收藏夹。

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注

Captcha Code