为何字面ID查询远快于子查询?SQL性能优化求助
问题解答
为什么子查询组合耗时20秒,字面ID查询却瞬间完成?
- 当使用
IN子查询时,数据库查询优化器可能未选择“先执行子查询得到28个ID,再用ID查找customer”的最优路径,反而将子查询逻辑与外层查询合并,执行了低效的关联操作(比如重复扫描表、不必要的嵌套循环),导致整体耗时剧增。 - 直接传入字面ID时,优化器能明确识别这是一组常量,会直接利用
idcustomer的主键索引(假设idcustomer是主键)快速定位对应记录,因此几乎不耗时。
如何在原查询中添加姓名字段且不耗时40秒?
方案1:使用CTE强制分步执行
通过公共表表达式先计算出符合条件的idcustomer集合,再关联customer表获取姓名字段,让优化器明确分步执行逻辑:
WITH filtered_customers AS ( SELECT c.idcustomer FROM sale s INNER JOIN customer c ON c.idCustomer = s.fkCustomer WHERE s.dateSale BETWEEN '1700-01-01' AND '2022-01-26' AND c.fkCompany = 'b92c5957-9275-4fa5-9970-1a41eb524328' ) SELECT c.firstname, c.lastname FROM customer c JOIN filtered_customers fc ON c.idcustomer = fc.idcustomer;
方案2:优化sale表的索引
原查询中sale表的过滤条件是dateSale,关联条件是fkCustomer,创建组合索引可大幅提升关联效率:
CREATE INDEX idx_sale_datesale_fkcustomer ON sale(dateSale, fkCustomer);
之后直接修改原查询返回姓名字段:
SELECT c.firstname, c.lastname FROM sale s INNER JOIN customer c ON c.idCustomer = s.fkCustomer WHERE s.dateSale BETWEEN '1700-01-01' AND '2022-01-26' AND c.fkCompany = 'b92c5957-9275-4fa5-9970-1a41eb524328';
该索引能让数据库快速筛选出符合日期的sale记录,再通过fkCustomer关联customer表的现有索引,避免RID查找的开销。
方案3:调整查询关联顺序
先从customer表筛选出符合fkCompany的记录,再关联sale表过滤日期,优化器可能选择更高效的执行路径:
SELECT c.firstname, c.lastname FROM customer c INNER JOIN sale s ON c.idCustomer = s.fkCustomer WHERE s.dateSale BETWEEN '1700-01-01' AND '2022-01-26' AND c.fkCompany = 'b92c5957-9275-4fa5-9970-1a41eb524328';
配合上述sale表的索引,能进一步提升查询速度。
内容的提问来源于stack exchange,提问作者Danilo Souza Morães
相关产品推荐
相关产品推荐

