Eu tenho duas consultas UPDATE que são semelhantes em estrutura, mas o plano de consulta do SQL Server para uma mostra índices sendo usados e para a outra mostra apenas uma verificação de tabela regular.
A seguir estão as consultas (de acordo com o plano de consulta, o nº 1 não usa índices, o nº 2 usa)-
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')
A segunda consulta usa um índice:
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')
A seguir está a definição da tabela:
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]
Como você pode ver, a única mudança na WHERE
cláusula é o uso de caracteres numéricos versus não numéricos (o que eu suspeito que não deve afetar o plano de consulta?)
Há um índice não clusterizado em cada uma das colunas EnrichedVendor e Vendor_No.
Qualquer ajuda seria apreciada.
ATUALIZAÇÃO: Incluindo os planos de consulta abaixo, e notei que a consulta nº 1 sugere um índice (em verde). Essa pode ser a solução para a resposta.
O SQL Server usa estatísticas para determinar um plano de execução. Se um índice estiver disponível, também estarão as estatísticas, e o servidor SQL determinará o caminho de menos trabalho. Isso pode estar usando o índice ou fazendo uma varredura na tabela.
No seu exemplo, o servidor SQL determinou que uma varredura de tabela é menos trabalhosa do que fazer uma busca de índice e uma pesquisa de favoritos.
O que você pode ver é que uma de suas consultas é "menos seletiva", ou seja, provavelmente atualiza mais registros, o que significa que mais pesquisas de favoritos são necessárias para satisfazer a segunda consulta. O servidor SQL apenas estimou que, para essa consulta, a soma de buscas de índice + pesquisas de favoritos é mais trabalhosa do que simplesmente fazer uma varredura de tabela.
Como o servidor SQL lê páginas inteiras, e não registros, sua consulta (conforme indicado pelas estatísticas) precisa ser seletiva o suficiente para o índice a ser usado, se o servidor SQL estimar que terá que ler todas as páginas de qualquer maneira, ele irá para um digitalização da tabela.
Veja aqui e aqui para uma explicação mais aprofundada com dados e resultados de amostra
O EnrichedVendor não é o mesmo nas consultas. Eu suspeito que quando você faz uma varredura de tabela, você está trabalhando com produtos onde o EnrichedVendor tem uma boa maioria de todos os registros da tabela e, portanto, faz sentido ler toda a tabela e o outro EnrichedVendor tem um percentil muito menor do total registros na tabela.
Mas você também pode precisar atualizar as estatísticas da tabela.
Você pode alterar a atualização? Em geral, as cláusulas "ou" são ruins para desempenho/uso de índice. Se você fizer 2 atualizações,
Primeira atualização com uma das chaves:
e o resto das linhas:
Normalmente, esse tipo de abordagem funciona melhor, mesmo que pareça mais complicado