SQL左连接两张万行表执行超60秒,如何优化至5秒以内?
性能瓶颈分析
- 最大开销来自WHERE子句的相关子查询:每扫描table1的一行数据,就要执行一次子查询计算同
key2_Table1分组下的最大时间,1万行数据就会触发1万次循环查询,是耗时超标的核心原因。 - 缺少对应索引:两张表的连接键、分组计算键没有索引的情况下,每次查询都要做全表扫描,进一步放大了开销。
- 全字段查询:
SELECT t.*,k.*拉取了所有冗余字段,增加了数据读取、传输和临时缓存的开销,尤其table2有50+字段,冗余数据占比极高。
优化方案
1. 改写SQL,替换相关子查询为窗口函数
用窗口函数一次性完成所有行的分组排序,只需要扫描一次table1即可筛选出每个key2_Table1分组下的最新时间行,避免逐行循环查询。改写后的SQL如下:
WITH latest_table1 AS ( SELECT -- 请替换为你实际需要的table1字段,禁止用*拉取全字段 key_Table1, key2_Table1, Time, [其他你需要的table1字段], ROW_NUMBER() OVER (PARTITION BY key2_Table1 ORDER BY Time DESC) AS rn FROM table1 ) SELECT -- 请替换为你实际需要的两个表的字段,禁止用*拉取全字段 lt.*, k.[需要的table2字段1], k.[需要的table2字段2], ... FROM latest_table1 AS lt LEFT JOIN table2 AS k ON lt.key_Table1 = k.Key_Table2 WHERE lt.rn = 1 ORDER BY lt.Time;
如果存在同一个key2_Table1有多条相同最大Time数据都需要保留的场景,把ROW_NUMBER替换为RANK即可。
2. 新增覆盖索引,消除全表扫描
在SQL Server中创建以下两个索引,直接通过索引就能完成分组筛选、连接匹配操作,无需回表读取数据:
- table1索引:
CREATE NONCLUSTERED INDEX idx_table1_key2_time ON table1 (key2_Table1, Time DESC) INCLUDE (key_Table1, [其他你在SELECT中用到的table1字段]) - table2索引:
CREATE NONCLUSTERED INDEX idx_table2_key ON table2 (Key_Table2) INCLUDE ([其他你在SELECT中用到的table2字段])
3. 移除冗余字段查询
严格按照实际需求列明查询字段,不要用*拉取全部字段,仅这一项优化通常就能减少30%以上的执行耗时。
以上优化全部完成后,1万行级别的数据量执行时间可稳定控制在1秒以内,完全满足5秒以内的要求。你碰到的SQL Server执行速度慢于Excel的反常情况,核心原因是原SQL的不合理写法带来的额外计算开销,优化后SQL Server的执行速度会远快于Excel处理同需求的速度。
内容的提问来源于stack exchange,提问作者DamnSpaceship
相关产品推荐
相关产品推荐

