查询优化 - 为什么这会加快查询速度?

时间:2009-08-28 15:43:40

标签: tsql optimization sql-server-2000 toad

我在SQL Server 2000 Server上使用Quest的TOAD for SQL Server。

这是我的问题:

SELECT CASE SLCE.GroupName WHEN 'Other' THEN ARM.FBCOMPANY 
                           WHEN 'Inter Co.' THEN ARM.FBCOMPANY 
                           ELSE SLCE.GroupName END AS [Company Name], 
       ARM.fcustno AS [Cust No], 
       ARM.fbcompany AS [Cust Name], 
       ARM.fcinvoice AS [Invoice No], 
       ARM.fdgldate AS [Post Date], 
       year(arm.fdgldate) AS [Year Posted], 
       CASE ARM.fcsource WHEN 'S' THEN 'Shipper' 
                         WHEN 'O' THEN 'Sales Order' 
                         WHEN 'R' THEN 'Receiver' 
                         WHEN 'C' THEN 'Customer' 
                         ELSE ARM.fcsource END AS [Source Doc Type], 
       CASE ARM.fcstatus WHEN 'N' THEN 'New' 
                         WHEN 'U' THEN 'Unpaid' 
                         WHEN 'P' THEN 'Partially Paid' 
                         WHEN 'F' THEN 'Paid in Full' 
                         WHEN 'H' THEN 'Held' 
                         WHEN 'V' THEN 'Voided' 
                         ELSE ARM.fcstatus END AS [Invoice Status], 
       ARM.fpono AS [Cust PO No], 
       ARM.fsalespn AS [Sales Person], 
       ARI.fitem AS [Item No], 
       ARI.fprodcl AS [Prod Class], 
       ARI.fshipkey AS [Qty Invoiced], 
       ARI.ftotprice AS [Net Invoiced], 
       ARI.fpartno AS [Part No], 
       ARI.frev AS [Part Rev], 
       cast(ARI.fmdescript AS VARCHAR(20)) AS [Part Description], 
       ARM.fsono AS [Sales No], 
       ARI.fsokey AS [SO Rels Key], 
       ARI.fordqty AS [Qty Ordered], 
       RED.[YEAR] AS [Year], 
       RED.PERIOD AS [RF Period] 
  FROM dbo.armast ARM 
       INNER JOIN dbo.aritem ARI 
          ON ARM.FCINVOICE = ARI.FCINVOICE 
       INNER JOIN slcdpm SLC 
          ON SLC.fcustno = ARM.fcustno 
       LEFT OUTER JOIN slcdpm_ext SLCE 
         ON SLC.identity_column = SLCE.fkey_id 
       INNER JOIN REDFRIDAYDATES..TBLREDFRIDAYALLDATES RED 
          ON RED.date = CAST (FLOOR (CAST (ARM.fdgldate AS FLOAT)) AS DATETIME) 
 WHERE ARM.fcstatus <> 'V' 
   AND RED.[YEAR] = year(getdate()) 
   AND ari.frev = 'REP' 
   AND ARI.fsalesacc IN ('4010001', '4010002', '4010003', '4010004', '4010005', '4010006', '4010007', '4010008', '4010009', '4010010', '4010018', '4010019', '4010020', '4010021', '4010031', '4010050', '4022000', '4031000', '4045000', '4055000', '4057000', '4060000', '4070000')

这是TOAD的选项(突出显示差异)是:

INNER JOIN dbo.aritem ARI 
          ON ARM.FCINVOICE = ***COALESCE (ARI.FCINVOICE , ARI.FCINVOICE)*** 
       INNER JOIN slcdpm SLC 
          ON SLC.fcustno = ARM.fcustno 
       LEFT OUTER JOIN slcdpm_ext SLCE 
         ON SLC.identity_column = SLCE.fkey_id 
       INNER JOIN REDFRIDAYDATES..TBLREDFRIDAYALLDATES RED 
          ON RED.date = CAST (FLOOR (CAST (ARM.fdgldate AS FLOAT)) AS DATETIME) 
 WHERE ARM.fcstatus <> 'V' 
   AND RED.[YEAR] = year(getdate()) 
   AND ari.frev = 'REP' 
   AND ARI.fsalesacc IN ('4010001', '4010002', '4010003', '4010004', '4010005', '4010006', '4010007', '4010008', '4010009', '4010010', '4010018', '4010019', '4010020', '4010021', '4010031', '4010050', '4022000', '4031000', '4045000', '4055000', '4057000', '4060000', '4070000') 
   ***AND ARI.[fpartno] >= CHAR(0)***

有人可以告诉我为什么合并和附加声明加快了这个查询的速度超过50%?

4 个答案:

答案 0 :(得分:3)

您是否看过实际执行计划?这些应该向您展示SQL Server在执行这些查询时采用的不同方法。

答案 1 :(得分:1)

这绝对是一个奇怪的。执行计划应该肯定地告诉你,但是在数据库中这样的性能变化几乎总是归结为索引。所以我最好的猜测是,某种程度上sql server缺少它可以使用的索引,并添加这些奇怪的更改使它更加突出。

但是如果你想要了解所涉及的'为什么',那么下次你可以把你的查询写得更快,那里真的没什么。

答案 2 :(得分:1)

完整的WAG:

我猜测fpartno上有一个“not null”条件(所以添加的过滤器总是通过),并且Toad碰巧知道SQLServer不够聪明,无法检测到&gt; = CHAR(0)总是如此。所以这表明Toad试图以非常倾斜的方式引导优化器使用其中包含fpartno的东西。那个东西可能是(fcinvoice,fpartno)的复合索引..你有其中一个吗?

与其他人一样,解释计划应该有助于解释这个谜团。

答案 3 :(得分:1)

这些更改都不会对查询的逻辑含义产生任何影响(即,它们是“无操作”)

COALESCE对ON子句的唯一物理影响是阻止优化器尝试使用ARI.FCINVOICE的索引。

同样,“&gt; = CHAR(0)”可能对优化器产生的唯一物理效果可能是为了考虑使用索引范围扫描(或搜索)在一个有ARI。[fpartno]的索引上。

所以我的结论是TOAD试图操纵优化器使用特定索引而不实际强制它使用带有显式HINT的索引。实际上,这有点聪明,因为T-SQL优化器提示的真正问题在于它们的依赖性和脆弱性。