Por que essa consulta simples recebe tanta memória?
-- Demo table
CREATE TABLE dbo.Test
(
TID integer IDENTITY NOT NULL,
FilterMe integer NOT NULL,
SortMe integer NOT NULL,
Unused nvarchar(max) NULL,
CONSTRAINT PK_dbo_Test_TID
PRIMARY KEY CLUSTERED (TID)
);
GO
-- 100,000 example rows
INSERT dbo.Test WITH (TABLOCKX)
(FilterMe, SortMe)
SELECT TOP (100 * 1000)
CHECKSUM(NEWID()) % 1000,
CHECKSUM(NEWID())
FROM sys.all_columns AS AC1
CROSS JOIN sys.all_columns AS AC2;
GO
-- Query
SELECT
T.TID,
T.FilterMe,
T.SortMe,
T.Unused
FROM dbo.Test AS T
WHERE
T.FilterMe = 567
ORDER BY
T.SortMe;
Para cerca de 50 linhas, o otimizador reserva quase 500 MB para a classificação:
Este é um bug no SQL Server (de 2008 a 2014 inclusive).
Meu relatório de bug está aqui .
A condição de filtragem é enviada para o operador de varredura como um predicado residual, mas a memória concedida para a classificação é calculada erroneamente com base na estimativa de cardinalidade pré-filtro .
Para ilustrar o problema, podemos usar o sinalizador de rastreamento 9130 (não documentado e sem suporte) para impedir que o filtro seja enviado para baixo no operador de digitalização. A memória concedida para a classificação agora é baseada corretamente na cardinalidade estimada da saída do filtro, não na varredura:
Para um sistema de produção , será necessário tomar medidas para evitar a forma de plano problemática (um filtro inserido em uma varredura com uma classificação em outra coluna). Uma maneira de fazer isso é fornecer um índice sobre a condição do filtro e/ou fornecer a ordem de classificação necessária.
Com esse índice instalado, a concessão de memória desejada para a classificação é de apenas 928 KB :
Indo além, o seguinte índice pode evitar completamente a classificação ( zero concessão de memória):
Testado e com bug confirmado nas seguintes compilações do SQL Server x64 Developer Edition:
Isso foi corrigido no SQL Server 2016 Service Pack 1 . As notas de versão incluem o seguinte:
Testado e confirmado corrigido em:
Microsoft SQL Server 2016 (SP1) - 13.0.4001.0 (X64) Developer Edition
Microsoft SQL Server 2014 (SP2-CU3) 12.0.5538.0 (X64) Developer Edition
Ambos os modelos CE.
Do SQL 2012 em diante, você pode procurar uma grande discrepância entre
SerialRequiredMemory
eSerialDesiredMemory
, por exemplo, algo assim:Algumas notas adicionais sobre esses novos atributos aqui . Esta consulta é um pouco grosseira e pronta, mas pegou a consulta de classificação excessiva da minha caixa de desenvolvimento do SQL Server 2014 com uma proporção de 975,47, além de alguns outros planos impressionantes. A proporção 'normal' (pelo menos em meus testes limitados) parece ser ~ 1.
HTH
Obrigado por toda a ajuda. Pensei em enviar uma versão atualizada da consulta acima que consideramos útil.