Este artigo discute um problema que ocorre durante uma consulta de um índice columnstore clusterizado no Microsoft SQL Server 2014. Este artigo fornece uma resolução para este problema.
Resumo
Quando você usa uma consulta que examina um índice columnstore clusterizado no Microsoft SQL Server 2014, pode, sob condições raras, receber resultados parciais da consulta.
Esse problema ocorre quando a operação a seguir é executada.
Etapa 1
Uma instrução Transact-SQL [INSERT ou BULK-INSERT] insere dados em uma tabela que tem índice columnstore clusterizado. Durante esta operação, as seguintes condições se aplicam:
- Quando a instrução Transact-SQL atinge o limite do rowgroup, ela fecha o rowgroup R1 que tem o segmento S1.
- O segmento S1 aponta para o dicionário local D1.
- A instrução continua a inserir linhas no novo rowgroup R2.
- Quando rowgroup R1 é fechado, o dicionário local D1 também não precisa ser fechado. Se o dicionário D1 ainda tiver espaço disponível, você poderá deixá-lo aberto e reutilizá-lo para o novo rowgroup R2.
Etapa 2
Se a instrução Transact-SQL for encerrada de forma anormal ou cancelada antes de fechar o novo rowgroup R2, as seguintes condições serão aplicadas:
- As alterações de metadados columnstore ocorrem em subtransações que são confirmadas independentemente da transação externa.
- Neste ponto, rowgroup R1 persiste na tabela do sistema em um estado "em construção" ou INVISÍVEL, e o segmento S1 faz referência ao dicionário D1.
- Não há nenhuma linha criada na tabela do sistema para o dicionário D1. Isso ocorre porque a instrução Transact-SQL nunca tem a oportunidade de fechar a linha existente. Portanto, a linha existente persiste.
Etapa 3
Em uma situação típica, se a tarefa em segundo plano do motor de tupla for iniciada após o término da instrução Transact-SQL, a tarefa em segundo plano removerá o rowgroup R1 invisível e o segmento S1. Se uma nova instrução Transact-SQL for iniciada agora e criar rowgroup R3 que tenha um novo segmento S3 que exija um novo dicionário local, você não poderá reutilizar a ID interna do dicionário D1. Isso ocorre porque o estado na memória do columnstore controla as IDs de dicionário usadas. Portanto, o segmento S3 fará referência ao novo dicionário D2.
Observação A condição nesta etapa é uma condição comum. Portanto, nenhuma corrupção ocorre.
Etapa 4
Se o SQL Server perder o estado na memória do dicionário D1 antes que a tarefa de movimentação de tupla entre em vigor (e execute conforme descrito na Etapa 3), ocorrerá o problema descrito neste artigo.
Anotações
Esse evento ocorre por qualquer um dos seguintes motivos:
- O SQL Server enfrenta sobrecarga de memória e o conteúdo na memória do dicionário D1 é removido da memória.
- A instância do SQL Server é reiniciada.
- O banco de dados que contém o índice columnstore clusterizado fica offline e, em seguida, volta a ficar online.
Depois que qualquer um desses eventos ocorre e o SQL Server recarrega as estruturas na memória, não há registro de que um dicionário D1 e sua ID interna existissem. Isso ocorre porque o dicionário D1 não foi retido nas tabelas do sistema quando a instrução Transact-SQL foi finalizada ou concebida.
Se a tarefa em segundo plano do motor de tupla for iniciada nesse ponto, não ocorrerão erros porque as condições descritas na Etapa 3 se aplicam.
Se um novo rowgroup R3 for criado antes do início da tarefa em segundo plano do motor de tupla (de acordo com o item de marcador anterior), o SQL Server atribuirá a mesma ID interna ao novo dicionário D1 e fará referência ao dicionário D1 para o segmento S3 no rowgroup R3.
Quando a tarefa em segundo plano do motor de tupla é iniciada após a ação anterior, ela descarta o rowgroup invisível R1 e seus segmentos S1 junto com o novo dicionário D1. Isso ocorre porque o motor de tupla considera que o novo dicionário D1 e o dicionário original D1 que S1 referencia são os mesmos.
Observação Quando essa condição ocorre, você não pode consultar o conteúdo do rowgroup R3.
Resolução
O problema foi corrigido pela primeira vez nas seguintes atualizações cumulativas para o SQL Server:
Atualização cumulativa 1 para o SQL Server 2014 SP1
Atualização cumulativa 8 para o SQL Server 2014
A correção para esse problema também está incluída nas seguintes atualizações de GDR (versão de distribuição geral):
Atualização de segurança do SQL Server 2014 QFE
Esta atualização inclui a Atualização Cumulativa 8, esta correção importante e as atualizações de segurança MS15-058 necessárias.
Atualização de segurança para o SQL Server 2014 GDR
Esta atualização inclui esta correção importante e correções de segurança cumulativas por meio do MS15-058.
Atualização não relacionada a segurança para o SQL Server 2014 Service Pack 1 GDR
Esta atualização inclui apenas esta correção importante.
Sobre atualizações cumulativas para o SQL Server
Cada nova atualização cumulativa do SQL Server contém todos os hotfixes e todas as correções de segurança incluídas na atualização cumulativa anterior. Confira as atualizações cumulativas mais recentes do SQL Server:
- Atualização cumulativa mais recente do SQL Server 2014 SP1
- Atualização cumulativa mais recente do SQL Server 2014
Mais informações
Mensagens de erroEm um banco de dados afetado no momento, se você executar DBCC CHECKDB depois de aplicar essa correção, receberá a seguinte mensagem de erro:
Observação
Mensagem 5289, Nível 16, Estado 1, Linha 1
O índice columnstore clusterizado 'cci' na tabela 't' tem um ou mais valores de dados que não correspondem aos valores de dados em um dicionário. Restaure os dados de um backup.
Em um banco de dados afetado no momento, ao executar uma consulta que examina as tabelas afetadas depois de aplicar essa correção, você receberá a seguinte mensagem de erro:
Observação
Mensagem 5288, Nível 16, Estado 1, Linha 1
O índice Columnstore tem um ou mais valores de dados que não correspondem aos valores de dados em um dicionário. Execute DBCC CHECKDB para obter mais informações.
Se você receber esses erros, poderá salvar os dados não corrompidos exportando em massa os dados de colunas/grupos de linhas não afetados e, em seguida, recarregando os dados depois de descartar ou criar o índice columnstore clusterizado. Você deve habilitar o sinalizador de rastreamento 10207 para suprimir o erro 5288 e reverter para o comportamento antigo de ignorar rowgroups corrompidos.
Observação: as mensagens de erro 5288 e 5289 são geradas para este rowgroup R3 que tem o segmento S3. O sinalizador de rastreamento 10207 é usado para extrair os segmentos do rowgroup R3 que não são afetados pelo dicionário D1 ausente.
Consulta de bancos de dados afetadosPara determinar se o banco de dados que contém índices columnstore já está afetado por esse problema, execute a seguinte consulta:
select
object_name(i.object_id) as table_name,
i.name as index_name,
p.partition_number,
count(distinct s.segment_id) as damaged_rowgroups
from
sys.indexes i
join sys.partitions p on p.object_id = i.object_id and p.index_id = i.index_id
join sys.column_store_row_groups g on g.object_id = i.object_id and g.index_id = i.index_id and g.partition_number = p.partition_number
join sys.column_store_segments s on s.partition_id = p.partition_id and s.segment_id = g.row_group_id
where
i.type in (5, 6)
and s.secondary_dictionary_id <> -1
and g.state_description = 'COMPRESSED'
and s.secondary_dictionary_id not in
(
select dictionary_id from sys.column_store_dictionaries d
where d.hobt_id = p.hobt_id and d.column_id = s.column_id
)
group by
object_name(i.object_id),
i.name,
p.partition_number
Anotações
Você deve executar essa consulta em todos os bancos de dados que contêm índices columnstore no servidor que está executando o SQL Server. Um conjunto de resultados vazio indica que o banco de dados não foi afetado.
Execute essa consulta durante um período em que não há atividade que crie novos rowgroups ou altere o estado dos rowgroups existentes. Por exemplo, as seguintes atividades podem modificar o estado de rowgroups: build de índice, reorganização de índice, inserção em massa, motor de tupla compactando repositórios delta.
Antes de executar a consulta, você pode desabilitar a tarefa de motor de tupla em segundo plano usando o sinalizador de rastreamento 634. Use este comando para desabilitar a tarefa em segundo plano: DBCC TRACEON ( 634 , -1 ). Depois que a consulta terminar a execução, lembre-se de reabilitar a tarefa em segundo plano usando o comando: DBCC TRACEOFF ( 634 , -1 ).
Verifique também se não há comandos BULK INSERT/BCP/SELECT-INTO inserindo dados nas tabelas que usam o índice columnstore enquanto essa consulta está em execução.
É recomendável usar essas etapas para evitar que a consulta retorne falsos positivos.
Status
A Microsoft confirmou que este é um problema nos produtos da Microsoft listados na seção "Aplica-se a".