排序与并行致SQL查询耗时过高,大数据集慢20-30倍求优化
优化你的SQL查询:大数据集下性能暴跌的原因和解决方案
首先,咱们直接揪出最可能的性能杀手:JOIN条件里的OR逻辑。你看这个连接:
LEFT OUTER JOIN ( SELECT [DESIGNATION], [TYPE], [BLDG], [LOCATION_ID] FROM [LTS].[dbo].[LTS_LOCATION] ) b ON a.[LAST_SEEN_LOC_ID] = b.[LOCATION_ID] OR b.[LOCATION_ID] = c.[LOCATION_ID]
这个OR在大数据集下是致命的——数据库没办法为这个条件使用有效的索引,只能做大量的行匹配(甚至是笛卡尔积级别的比对)。小数据集(1万行)的时候数据量小,这种开销不明显,但到50万+行时,计算量直接呈指数级增长,这就是你看到资源占用飙到20000、速度慢20-30倍的核心原因。
接下来,咱们一步步优化:
1. 重构OR连接条件,避免索引失效
把带OR的LEFT JOIN拆成两个独立的LEFT JOIN,然后用UNION ALL合并结果(如果有重复行可以用UNION,但UNION ALL更快)。这样数据库可以分别为每个JOIN条件利用索引,大幅减少匹配开销。
2. 去掉不必要的子查询
你现在用的子查询(比如SELECT ... FROM LTS_CONTAINER)完全没必要,直接JOIN原表即可。子查询会限制SQL Server优化器的执行计划选择,直接JOIN原表能让优化器更好地评估连接顺序和索引使用。
3. 添加针对性的索引
针对JOIN列、WHERE过滤列、ORDER BY列创建非聚集索引,让数据库快速定位数据:
- 对
LTS_PACKAGE的JOB_NUMBER、LAST_SEEN_LOC_ID、CONTAINER_ID创建复合索引(包含查询需要的其他列更好,即覆盖索引) - 对
LTS_LOCATION的LOCATION_ID、TYPE创建索引,包含DESIGNATION、BLDG - 对
LTS_DISCRETE_JOB_SUMMARY的DISCRETE_JOB_NUMBER、PLANNED_MFG_DELIVERY_DATE创建索引,包含其他需要的列 - 对
LTS_CONTAINER的CONTAINER_ID创建索引,包含DESIGNATION、LOCATION_ID
4. 优化后的查询示例
SELECT a.[RFIDTAGID], a.[JOB_NUMBER], d.[PROJECT_NUMBER], a.[PART_NUMBER], a.[QUANTITY], b.[DESIGNATION] as LOCATION, c.[DESIGNATION] as CONTAINER, a.[LAST_SEEN_TIME], b.[TYPE], b.[BLDG], d.[PBG], d.[PLANNED_MFG_DELIVERY_DATE], d.[EXTENSION_DATE], a.[ORG_ID] FROM [LTS].[dbo].[LTS_PACKAGE] as a LEFT OUTER JOIN [LTS].[dbo].[LTS_CONTAINER] c ON a.[CONTAINER_ID] = c.[CONTAINER_ID] LEFT OUTER JOIN [LTS].[dbo].[LTS_LOCATION] b ON a.[LAST_SEEN_LOC_ID] = b.[LOCATION_ID] INNER JOIN [LTS].[dbo].[LTS_DISCRETE_JOB_SUMMARY] d ON a.[JOB_NUMBER] = d.[DISCRETE_JOB_NUMBER] WHERE d.[PLANNED_MFG_DELIVERY_DATE] <= GETDATE() AND b.[TYPE] NOT IN('MFG', 'Manufacturing') AND (b.[DESIGNATION] IS NOT NULL OR c.[DESIGNATION] IS NOT NULL) UNION ALL SELECT a.[RFIDTAGID], a.[JOB_NUMBER], d.[PROJECT_NUMBER], a.[PART_NUMBER], a.[QUANTITY], b.[DESIGNATION] as LOCATION, c.[DESIGNATION] as CONTAINER, a.[LAST_SEEN_TIME], b.[TYPE], b.[BLDG], d.[PBG], d.[PLANNED_MFG_DELIVERY_DATE], d.[EXTENSION_DATE], a.[ORG_ID] FROM [LTS].[dbo].[LTS_PACKAGE] as a LEFT OUTER JOIN [LTS].[dbo].[LTS_CONTAINER] c ON a.[CONTAINER_ID] = c.[CONTAINER_ID] LEFT OUTER JOIN [LTS].[dbo].[LTS_LOCATION] b ON b.[LOCATION_ID] = c.[LOCATION_ID] INNER JOIN [LTS].[dbo].[LTS_DISCRETE_JOB_SUMMARY] d ON a.[JOB_NUMBER] = d.[DISCRETE_JOB_NUMBER] WHERE d.[PLANNED_MFG_DELIVERY_DATE] <= GETDATE() AND b.[TYPE] NOT IN('MFG', 'Manufacturing') AND (b.[DESIGNATION] IS NOT NULL OR c.[DESIGNATION] IS NOT NULL) AND a.[LAST_SEEN_LOC_ID] != b.[LOCATION_ID] -- 避免和第一个查询重复 ORDER BY [JOB_NUMBER], d.[PLANNED_MFG_DELIVERY_DATE] desc, [RFIDTAGID];
额外建议
- 更新统计信息:执行
UPDATE STATISTICS [LTS].[dbo].[LTS_PACKAGE](以及其他涉及的表),过时的统计信息会让SQL Server优化器选错执行计划。 - 查看执行计划:在SQL Server Management Studio里点击“显示估计的执行计划”,看看有没有全表扫描、哈希匹配(如果可以用嵌套循环或合并连接更好)的操作,这些都是性能瓶颈的信号。
内容的提问来源于stack exchange,提问作者Ben F.
相关产品推荐
相关产品推荐

