我有两个结构相似的 UPDATE 查询,但一个的 SQL Server 查询计划显示正在使用的索引,另一个只显示常规表扫描。
以下是查询(根据查询计划,#1 不使用索引,#2 使用)-
UPDATE Payment_Metadata
SET
Payment_Metadata.CommodityCode = 'RAW MATERIALS',
Payment_Metadata.C1 = 'RAW MATERIALS',
Payment_Metadata.C2 = 'INGREDIENTS',
Payment_Metadata.C3 = 'OTHER ',
Payment_Metadata.RuleText = '---',
Payment_Metadata.LastUpdatedIndex = Payment_Metadata.LastUpdatedIndex + 1,
Payment_Metadata.IsExcluded = 0,
Payment_Metadata.LogText = 'Commodity>Raw Materials>Ingredients>Other'
FROM
Payment_Metadata
WHERE
Payment_Metadata.IsProcessed = 0
AND (Payment_Metadata.EnrichedVendor = 'NFL'
OR Payment_Metadata.Vendor_No = 'NFL')
第二个查询使用索引:
UPDATE Payment_Metadata
SET
Payment_Metadata.CommodityCode = 'RAW MATERIALS',
Payment_Metadata.C1 = 'RAW MATERIALS',
Payment_Metadata.C2 = 'INGREDIENTS',
Payment_Metadata.C3 = 'OTHER ',
Payment_Metadata.RuleText = '---',
Payment_Metadata.LastUpdatedIndex = Payment_Metadata.LastUpdatedIndex + 1,
Payment_Metadata.IsExcluded = 0,
Payment_Metadata.LogText = 'Commodity>Raw Materials>Ingredients>Other'
FROM
Payment_Metadata
WHERE Payment_Metadata.IsProcessed = 0
AND (Payment_Metadata.EnrichedVendor = '0202054' OR
Payment_Metadata.Vendor_No = '0202054')
以下是表定义:
CREATE TABLE [dbo].[Payment_Metadata](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Company_Code] [varchar](1024) NULL,
[Comp_Code_Desc] [varchar](1024) NULL,
[Vendor_Acct_Group] [varchar](1024) NULL,
[Vendor_No] [varchar](10) NULL,
[Vendor_Name] [varchar](1024) NULL,
[Vendor_ABN] [varchar](1024) NULL,
[Vendor_PTerm] [varchar](1024) NULL,
[Vendor_PTerm_Desc] [varchar](1024) NULL,
[Purchasing_Group] [varchar](1024) NULL,
[Purchasing_Group_Des] [varchar](1024) NULL,
[PO_DocType] [varchar](1024) NULL,
[PO_DocType_Desc] [varchar](1024) NULL,
[Purchasing_Document] [varchar](1024) NULL,
[PO_Date] [varchar](1024) NULL,
[PO_CreatedBy] [varchar](1024) NULL,
[Plant] [int] NULL,
[Item_Number] [varchar](1024) NULL,
[Material_Number] [varchar](1024) NULL,
[Material_Group] [varchar](7) NULL,
[Material_Group_Desc] [varchar](1024) NULL,
[Account_Assignment] [varchar](32) NULL,
[Acct_Assignment_Desc] [varchar](1024) NULL,
[GL_Account] [varchar](7) NULL,
[GL_Account_Desc] [varchar](1024) NULL,
[PO_Desc] [varchar](64) NULL,
[PO_Quantity] [decimal](10, 2) NULL,
[Order_UOM] [varchar](1024) NULL,
[Order_Price_Unit] [varchar](1024) NULL,
[Invoice_Receipt] [varchar](1024) NULL,
[Invoice_Reference] [varchar](1024) NULL,
[Invoice_Date] [datetime] NOT NULL,
[Invoice_Scan_Date] [datetime] NULL,
[Invoice_Item] [int] NULL,
[Invoice_Amount] [decimal](15, 2) NULL,
[GST] [decimal](10, 2) NOT NULL,
[Invoice_Gross_Amount] [decimal](15, 2) NULL,
[Currency] [varchar](1024) NULL,
[Document_Type] [varchar](1024) NULL,
[Document_Number] [varchar](1024) NULL,
[Document_Date] [datetime] NOT NULL,
[Posting_Date] [datetime] NOT NULL,
[Payment_Term] [varchar](1024) NULL,
[Baseline_Date] [datetime] NOT NULL,
[Due_Date] [datetime] NOT NULL,
[Payment_Document] [varchar](1024) NULL,
[Clearing_Date] [datetime] NOT NULL,
[CommodityCode] [varchar](128) NULL,
[RuleText] [nvarchar](max) NULL,
[IsProcessed] [bit] NOT NULL,
[DataSource] [varchar](5) NULL,
[IsContracted] [bit] NOT NULL,
[IsPreferred] [bit] NOT NULL,
[VendorRiskScore] [varchar](5) NULL,
[EnrichedVendor] [varchar](128) NULL,
[LastUpdatedIndex] [int] NOT NULL,
[LogText] [nvarchar](max) NULL,
[IsExcluded] [bit] NOT NULL,
[C1] [varchar](50) NULL,
[C2] [varchar](50) NULL,
[C3] [varchar](50) NULL,
[OriginalVendor] [varchar](60) NULL,
[AdjustedAmount] [decimal](15, 2) NULL
) ON [PRIMARY]
如您所见,该WHERE
子句中唯一的变化是数字与非数字字符的使用(我怀疑这不应该影响查询计划?)
EnrichedVendor 和 Vendor_No 列中的每一列都有一个非聚集索引。
任何帮助,将不胜感激。
更新:包括下面的查询计划,我注意到查询 #1 建议一个索引(绿色)。这可能是答案的解决方案。
SQL Server 使用统计信息来确定执行计划。如果索引可用,统计信息也可用,SQL Server 将确定最少工作的路径。这可能是使用索引或进行表扫描。
在您的示例中,SQL 服务器已确定表扫描比进行索引查找和书签查找的工作量少。
您可以看到您的其中一个查询“选择性较低”,即它可能更新更多记录,这意味着需要更多书签查找来满足第二个查询。SQL Server 刚刚估计,对于该查询,索引查找 + 书签查找的总和比简单地进行表扫描要多。
由于 SQL Server 读取整个页面,而不是记录,因此您的查询(如统计数据所示)需要具有足够的选择性才能使用索引,如果 SQL Server 估计它无论如何都必须读取每一页,那么它将去表扫描。
有关示例数据和结果的更深入解释,请参见此处和此处
查询中的 EnrichedVendor 不一样。我怀疑当您进行表扫描时,您正在使用 EnrichedVendor 在表中的所有记录中占绝大多数的产品,因此读取所有表是有意义的,而另一个 EnrichedVendor 占总数的百分比要小得多表中的记录。
但您也可能只需要更新表的统计信息。
你能改变更新吗?一般来说,“或”子句对性能/索引使用不利。如果您要进行 2 次更新,
首先使用其中一个键进行更新:
和其余的行:
通常这种方法效果更好,即使它看起来更复杂