Estou tentando inserir o conjunto de resultados de:
SELECT * FROM sys.database_scoped_configurations
em uma tabela temporária, porque quero verificar as configurações de todos os bancos de dados no meu servidor. Então eu escrevi este código:
DROP TABLE IF EXISTS #h
CREATE TABLE #h(dbname sysname, configuration_id INT, name sysname, value SQL_VARIANT, value_for_secondary SQL_VARIANT)
EXEC sys.sp_MSforeachdb 'USE ?; insert into #h(dbname, configuration_id, name, value,value_for_secondary) SELECT ''?'' as dbname, * FROM sys.database_scoped_configurations D'
SELECT * FROM #h H
Mas haverá apenas uma linha por banco de dados, não as quatro linhas que eu espero executar uma seleção simples em cada banco de dados.
Eu sei que existem maneiras melhores de codificar isso do que usar sp_MSForEachDB, e eu tentei várias. Mas ainda recebo apenas uma linha por banco de dados. Eu tentei isso no SQL Server 2016 RTM e no SP1
Isso é um erro do SQL Server 2016 ou estou fazendo algo errado?
sql-server
configuration
sql-server-2016
Henrik Staun Poulsen
fonte
fonte
Respostas:
Sim. Definitivamente, este não é um comportamento correto. Eu relatei aqui e foi corrigido no SQL Server 2016 SP2 CU9 .
Como Mikael Eriksson diz nos comentários
sys.database_scoped_configurations
esys.dm_exec_sessions
são implementados como visualizações no formatoNo entanto, comparando os dois planos abaixo, há uma diferença óbvia.
A saída do sinalizador de rastreamento 8619 para ambas as consultas mostra
Aparentemente, o SQL Server não é capaz de verificar se a fonte do TVF também não é o destino da inserção, portanto, requer proteção de Halloween.
No caso das sessões, isso foi implementado como um spool que captura todas as linhas primeiro. No
database_scoped_configurations
adicionando umTOP 1
ao plano. O uso daTOP
proteção de Halloween é discutido neste artigo . O artigo também menciona um sinalizador de rastreamento não documentado para forçar um spool em vez deTOP
funcionar conforme o esperado.Um problema óbvio com o uso em
TOP 1
vez de um spool é que ele arbitrariamente limitará o número de linhas inseridas. Portanto, isso só seria válido se o número de linhas retornadas pela função fosse <= 1.A nota inicial se parece com isso
Compare isso com o memorando inicial da consulta 2
Se entendi o que foi dito corretamente, ele acha que o primeiro TVF pode retornar no máximo uma linha e, portanto, aplica uma otimização incorreta. O máximo para a segunda consulta está definido como
1.34078E+154
(2^512
).Não faço ideia de onde esse número máximo de linhas é derivado. Talvez os metadados fornecidos pelo autor do DMV? Também é estranho que a
TOP(50)
solução alternativa não seja reescritaTOP(1)
porqueTOP(50)
não impediria a ocorrência do problema do Dia das Bruxas (mas impediria que continuasse indefinidamente)fonte
Por favor, pare de usar
sp_MSForEachDB
. É sem suporte, sem documentos e com erros - o que pode ser o problema aqui. Minha substituição demonstra o mesmo problema aqui, mas em geral é uma coisa mais segura de usar.Para coisas como essa, prefiro gerar SQL dinâmico do que entregar um único comando a um procedimento para executar várias vezes (mesmo o meu procedimento, no qual confio muito mais), dessa forma, posso simplesmente imprimir os comandos em vez de executá-los, e certifique-se de que todos farão o que dizem.
Partindo da observação de que o código subjacente à visualização do sistema implementa a
TOP (1)
, podemos tentar desta maneira:Observe que eu não uso
USE
aqui, mas prefixe asys
exibição do catálogo com o nome do banco de dados.Por que a visão funciona de maneiras mágicas, eu não sei; Não sei se você receberá uma boa resposta aqui, pois provavelmente requer comentários da Microsoft (ou de qualquer pessoa com acesso ao código-fonte ou que esteja disposto a acionar um depurador).
fonte
Obrigado por comunicar este problema!
Este é realmente um bug na maneira como o Query Optimizer gera um plano para a
sys.database_scoped_configurations
exibição do catálogo. Abordaremos isso em uma das próximas atualizações do SQL Server 2016 e no Banco de Dados SQL do Azure.Como solução alternativa, você pode adicionar uma
TOP
cláusula naSELECT
parte de sua inserção para obter o plano correto, por exemplo:fonte
Concordo que isso é muito estranho e um bug em potencial, mas a adição de um TOP (50), por exemplo, ao seu select realmente retorna todas as linhas, de modo que pelo menos o ajudaria. O resultado parece estar vindo de uma função de valor de tabela do sistema ([DB_SCOPED_CONFIG]), então não consigo realmente dizer o que está acontecendo.
Eu vou ficar de olho nesse tópico para ver se as pessoas mais 'inteligentes' sabem por que isso está acontecendo.
fonte