1

我在 SQL Server 2000 服务器上使用 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

4 回答 4

3

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

于 2009-08-28T15:46:42.143 回答
1

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

但是,如果您想了解所涉及的“为什么”,以便下次您可以首先编写查询更快,那么那里真的什么都没有。

于 2009-08-28T15:54:39.147 回答
1

完整的 WAG:

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

就像其他人所说的那样,解释计划应该有助于解释这个谜团。

于 2009-08-28T16:05:06.820 回答
1

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

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

同样,">= CHAR(0)" 可能对优化器产生的唯一物理影响可能是促使它考虑对具有 ARI.[fpartno] 的索引使用索引范围扫描(或搜索)它。

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

于 2009-08-28T16:16:50.430 回答