Em um servidor de controle de qualidade com memória muito baixa, tive o erro 8545 ao criar índices columnstore clusterizados em novas tabelas no SQL Server 2016:
Erro 8645: Ocorreu um tempo limite ao aguardar recursos de memória para executar a consulta. Execute novamente a consulta.
Posso reproduzir facilmente uma grande concessão de memória solicitada em minha máquina local. Para o seguinte código:
DROP TABLE IF EXISTS dbo.MY_FIRST_FACT_TABLE;
CREATE TABLE dbo.MY_FIRST_FACT_TABLE (
ID BIGINT NOT NULL,
COL1 BIGINT NULL,
COL2 BIGINT NULL,
COL3 BIGINT NULL,
COL4 BIGINT NULL,
COL5 BIGINT NULL,
COL6 BIGINT NULL,
COL7 BIGINT NULL,
COL8 BIGINT NULL,
COL9 BIGINT NULL,
COL10 BIGINT NULL,
STRING1 VARCHAR(100) NULL,
STRING2 VARCHAR(100) NULL,
STRING3 VARCHAR(100) NULL,
STRING4 VARCHAR(100) NULL,
STRING5 VARCHAR(100) NULL
);
CREATE CLUSTERED COLUMNSTORE INDEX MY_FIRST_CCI ON dbo.MY_FIRST_FACT_TABLE;
Recebo uma solicitação de memória de cerca de 512 MB de memória. Há um aviso para a concessão de memória excessiva no plano de execução real:
Mesmo que a consulta use 0 KB de memória, ela ainda pode expirar dependendo de outra atividade no servidor. Por que o SQL Server solicita tanta memória? O que posso fazer sobre isso?
Há uma dica sobre isso na documentação do desempenho da consulta CCI :
Essa citação sugere que o número de linhas na tabela é importante para o DOP, mas não para a concessão de memória. A memória necessária também depende do número de colunas, então vamos testar com uma tabela com menos colunas para ver mais facilmente a diferença esperada na concessão de memória. Estou usando esta tabela e definição de índice:
Abaixo estão os resultados de alguns testes:
Com 0 linhas, o DOP é rebaixado para 1, mas, caso contrário, o número de linhas não parece importar para a concessão de memória. Isso é, sem dúvida, uma simplificação grosseira, mas talvez o SQL Server construa o CCI um rowgroup por vez por DOP e mantenha os dicionários de string à medida que avança. Isso soa bem na prática e significa que a concessão de memória não será dimensionada com o número de linhas na tabela, mas sem uma verificação de um número muito baixo de linhas, o SQL Server poderá solicitar uma concessão de memória excessiva. A concessão de memória excessiva não importa na maioria dos casos porque
CREATE INDEX
é muito rápida, mas pode ser importante se o SQL Server aguardar a concessão de memória.Então agora eu tenho uma idéia de por que a concessão de memória é tão grande, mas o que pode ser feito sobre isso? O SQL Server 2014 introduziu a sintaxe para definir uma definição de índice como parte da definição de tabela. É possível escrever uma única instrução que cria a tabela e o índice :
Para a tabela original, a sintaxe ficaria assim:
Uma
CREATE TABLE
instrução não gera um plano real, então não posso dizer imediatamente se isso reduziu a concessão de memória. Tentei criar a tabela 1000 vezes enquanto martelava osys.dm_exec_query_memory_grants
DMV, mas nunca obtive nenhum resultado. Isso sugere que a memória não foi concedida, mas não é prova. Eu também tentei eventos estendidos com query_memory_grant_usage e não obtive nenhum resultado para aCREATE TABLE
instrução única.Obviamente, a melhor maneira de testar é criar o CCI nas condições de fluxo de trabalho originais com memória disponível limitada. Eu fiz isso e não experimentei nenhum tempo limite de memória.
Suponho que se possa dizer que definir o CCI na
CREATE TABLE
declaração para uma nova tabela é uma prática recomendada. No entanto, se sua carga de trabalho causar esse erro, alterar oCREATE TABLE
script provavelmente não será suficiente para resolver outros problemas que você encontrará, como problemas de memória ao iniciar o carregamento de dados nos CCIs.