You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

SQL查询运行过慢排查及性能优化咨询

优化您的慢SQL查询:问题分析与解决方案

让我们一步步拆解你的慢查询问题,然后给出针对性的优化方案:

首先,找出导致查询变慢的核心问题

  1. 函数调用让索引彻底失效:你在DateCreated列上用了CONVERT函数转换日期格式,这会让数据库无法使用该列上的任何索引,只能被迫做全表扫描——这绝对是慢查询的头号元凶。
  2. 逻辑运算符优先级搞乱了过滤逻辑OR的优先级比AND低,所以原查询里的AND DefaultVendorName IN (...) OR ProductIdentifier IN (...)会被数据库解析成(前面所有AND条件) OR (ProductIdentifier的条件),这不仅可能不符合你的业务逻辑,还会让数据库无法高效过滤数据,进一步拖慢速度。
  3. 不必要的LEFT JOIN变味了:你在CTE里用了LEFT JOIN productmasterlist,但紧接着在WHERE里过滤了DefaultVendorName(属于PM表),这会让LEFT JOIN自动变成INNER JOIN——因为只有匹配到PM的行才会被保留,这不仅逻辑上可能偏离你的预期,还平白增加了关联开销。
  4. 冗余的计算和数据传输:CTE里SELECT了一大堆你根本用不到的列,而且CTE和主查询重复过滤了相同的日期范围,额外消耗了内存和IO资源。

接下来,针对性的优化步骤

1. 修复日期过滤,彻底告别全表扫描

把对DateCreated的函数调用去掉,改成直接比较时间范围:

-- 原写法(会导致索引失效)
CONVERT(ID.DateCreated, DATE) >= '2014-01-01' 
AND CONVERT(ID.DateCreated, DATE) <= '2014-12-31'

-- 优化后(可以直接用索引)
ID.DateCreated >= '2014-01-01' 
AND ID.DateCreated < '2015-01-01'

这样数据库就能直接利用DateCreated列上的索引(如果还没建索引,赶紧给这个列加一个!)。

2. 用括号明确逻辑优先级

把OR的条件用括号包起来,确保过滤逻辑符合你的业务需求:

AND (
    PM.DefaultVendorName IN ('Simply Mac Trade In', 'Phobio')
    OR ID.ProductIdentifier IN ('ISATNS000001','ISATRB000003', ...)
)

3. 精简CTE,只保留必要数据

你的CTE只需要InvoiceIDByStore来关联主表,所以没必要SELECT一堆无关列,甚至可以用DISTINCT去重,减少后续JOIN的数据量:

WITH ValidInvoices AS (
    SELECT DISTINCT ID.InvoiceIDByStore
    FROM simplymacstaging.productdetail ID
    JOIN simplymacstaging.productmasterlist PM 
        ON PM.ProductSKU = ID.ProductIdentifier
    WHERE ID.DateCreated >= '2014-01-01' 
      AND ID.DateCreated < '2015-01-01'
      AND ID.InvoicedAt IN ('100 Park City', '101 Orem', ...)
      AND (
          PM.DefaultVendorName IN ('Simply Mac Trade In', 'Phobio')
          OR ID.ProductIdentifier IN ('ISATNS000001','ISATRB000003', ...)
      )
)

4. 给关键列加索引

确保以下列上有合适的索引:

  • productdetail.DateCreated:用于快速过滤日期范围
  • productdetail.InvoiceIDByStore:提升JOIN操作的效率
  • productdetail.ProductIdentifier:加快产品ID的过滤
  • productmasterlist.ProductSKU + productmasterlist.DefaultVendorName:如果保留这个JOIN,组合索引能让过滤更高效

5. 优化后的完整SQL示例

WITH ValidInvoices AS (
    SELECT DISTINCT ID.InvoiceIDByStore
    FROM simplymacstaging.productdetail ID
    JOIN simplymacstaging.productmasterlist PM 
        ON PM.ProductSKU = ID.ProductIdentifier
    WHERE ID.DateCreated >= '2014-01-01' 
      AND ID.DateCreated < '2015-01-01'
      AND ID.InvoicedAt IN ('100 Park City', '101 Orem', '102 Fort Union', '105 St. George', '106 Foothill')
      AND (
          PM.DefaultVendorName IN ('Simply Mac Trade In', 'Phobio')
          OR ID.ProductIdentifier IN ('ISATNS000001','ISATRB000003', 'ISPHNR000007','COMINS001595','COMIRB001597','ISPHNS000003', 'COMINS001415','ISPHRB000004','COMIRB001416','ISPHTL000006', 'IABUAP000004','IABUAP000003','MIMICE000035','MIMICE000426', 'MIMICE000427','IABUAP000006','COMIAP000007','COMICE000011')
      )
)
SELECT PD.* -- 建议替换成你实际需要的列,不要用*
FROM simplymacstaging.productdetail PD
JOIN ValidInvoices VI 
    ON VI.InvoiceIDByStore = PD.InvoiceIDByStore
WHERE PD.DateCreated >= '2014-01-01' 
  AND PD.DateCreated < '2015-01-01'

额外小贴士

  • 运行数据库的执行计划命令(比如MySQL的EXPLAIN,SQL Server的SET SHOWPLAN_XML ON),查看索引是否被正确使用,有没有全表扫描的情况。
  • 如果InvoiceIDByStore是发票的唯一标识,给它加个唯一索引或者主键,JOIN速度会更快。
  • 别用SELECT *,只选你需要的列,能减少数据传输和内存占用。

内容的提问来源于stack exchange,提问作者PrasadD

火山引擎 最新活动