我有一个存储过程,最近遇到了一些问题,最后我把它缩小到1 SELECT。问题是我无法弄清楚究竟发生了什么事情来破坏这一个查询的性能。我重写了它,但我不确定重写是完全相同的数据。
原始查询:
SELECT
@userId, p.job, p.charge_code, p.code
, (SELECT SUM(b.total) FROM dbo.[backorder w/total] b WHERE b.ponumber = p.ponumber AND b.code = p.code)
, ISNULL(jm.markup, 0)
, (SELECT SUM(b.TOTAL_TAX) FROM dbo.[backorder w/total] b WHERE b.ponumber = p.ponumber AND b.code = p.code)
, p.ponumber
, p.billable
, p.[date]
FROM dbo.PO p
INNER JOIN dbo.JobCostFilter jcf
ON p.job = jcf.jobno AND p.charge_code = jcf.chargecode AND jcf.userno = @userId
LEFT JOIN dbo.JobMarkup jm
ON jm.jobno = p.job
AND jm.code = p.code
LEFT JOIN dbo.[Working Codes] wc
ON p.code = wc.code
INNER JOIN dbo.JOBFILE j
ON j.JOB_NO = p.job
WHERE (wc.brcode <> 4 OR @BmtDb = 0)
GROUP BY p.job, p.charge_code, p.code, p.ponumber, p.billable, p.[date], jm.markup, wc.brcode
此查询实际上永远不会完成运行。它实际上超过了我们的一些更大的工作。
如果我将select中的2个子查询更改为像连接一样读取:
SELECT
@userid, p.job, p.charge_code, p.code
, (SELECT SUM(b.TOTAL))
, ISNULL(jm.markup, 0)
, (SELECT SUM(b.TOTAL_TAX))
, p.ponumber, p.billable, p.[date]
FROM dbo.PO p
INNER JOIN dbo.JobCostFilter jcf
ON p.job = jcf.jobno AND p.charge_code = jcf.chargecode AND jcf.userno = 11190030
INNER JOIN [BACKORDER W/TOTAL] b
ON P.PONUMBER = b.ponumber AND P.code = b.code
LEFT JOIN dbo.JobMarkup jm
ON jm.jobno = p.job
AND jm.code = p.code
LEFT JOIN dbo.[Working Codes] wc
ON p.code = wc.code
INNER JOIN dbo.JOBFILE j
ON j.JOB_NO = p.job
WHERE (wc.brcode <> 4 OR @BmtDb = 0)
GROUP BY p.job, p.charge_code, p.code, p.ponumber, p.billable, p.[date], jm.markup, wc.brcode
数据看起来与我几乎完全相同(尽管整体上有数千行,所以我可能错了),并且它运行得非常快。
任何想法都赞赏..
答案 0 :(得分:2)
在第二个查询中,您的逻辑读取次数较少,因为表[BACKORDER W / TOTAL]仅扫描一次。在第一个查询中,两个独立的子查询以独立方式处理,并且表被扫描两次,尽管两个子查询具有相同的谓词。
如果要检查两个查询是否返回相同的结果集,可以使用EXCEPT运算符:
如果两个陈述:
第一个SELECT查询... 除了 第二个SELECT查询...
和
第二个SELECT查询.. 除了 第一个SELECT查询...
返回一个空集,结果集是相同的。
答案 1 :(得分:1)
就正确性而言,您在第二个查询中inner join
[BACKORDER W/TOTAL]
,因此如果第一个查询在子查询中具有Null
值,则第二个查询中的这些行将丢失查询。
对于性能,优化器是一种启发式方法 - 它有时会使用非常糟糕的查询计划,即使是最小的更改也有时会导致完全不同的查询计划。您最好的机会是比较查询计划,看看是什么导致了差异。