Estoy tratando de insertar el conjunto de resultados de:
SELECT * FROM sys.database_scoped_configurations
en una tabla temporal, porque quiero verificar la configuración de todas las bases de datos en mi servidor. Entonces escribí 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
Pero entonces solo habrá una fila por base de datos, no las cuatro filas que espero de ejecutar una selección simple en cada base de datos.
Sé que hay mejores formas de codificar esto que usando sp_MSForEachDB, y probé varias. Pero todavía obtengo solo una fila por base de datos. He intentado esto en SQL Server 2016 RTM y SP1
¿Es esto un error con SQL Server 2016 o estoy haciendo algo mal?
sql-server
configuration
sql-server-2016
Henrik Staun Poulsen
fuente
fuente
Respuestas:
Si. Definitivamente este no es el comportamiento correcto. Lo informé aquí y se solucionó en SQL Server 2016 SP2 CU9 .
Como dice Mikael Eriksson en los comentarios
sys.database_scoped_configurations
ysys.dm_exec_sessions
se implementan como vistas en el formatoSin embargo, al comparar los dos planes a continuación, hay una diferencia obvia.
La salida del indicador de rastreo 8619 para ambas consultas muestra
SQL Server aparentemente no puede determinar que la fuente del TVF no sea también el objetivo de inserción, por lo que requiere protección de Halloween.
En el caso de las sesiones, esto se implementó como un carrete que captura todas las filas primero. En el
database_scoped_configurations
mediante la adición de unTOP 1
al plan. El uso deTOP
para la protección de Halloween se trata en este artículo . El artículo también menciona una marca de rastreo indocumentada para forzar un carrete en lugar deTOP
que funcione como se esperaba.Un problema obvio con el uso en
TOP 1
lugar de un carrete es que limitará arbitrariamente el número de filas insertadas. Por lo tanto, esto solo sería válido si el número de filas devueltas por la función fuera <= 1.El memo inicial se ve así
Compare esto con la nota inicial para la consulta 2
Si entiendo correctamente lo anterior, creo que el primer TVF puede devolver un máximo de una fila y, por lo tanto, aplica una optimización incorrecta. El valor máximo para la segunda consulta se establece en
1.34078E+154
(2^512
).No tengo idea de dónde se deriva este recuento de filas máximo. ¿Quizás los metadatos proporcionados por el autor del DMV? También es extraño que la
TOP(50)
solución no se vuelva a escribirTOP(1)
porqueTOP(50)
no evitaría que ocurriera el problema de Halloween (aunque evitaría que continuara indefinidamente)fuente
Por favor deja de usar
sp_MSForEachDB
. No es compatible, no está documentado y tiene errores, lo que puede ser el problema aquí. Mi reemplazo muestra el mismo problema aquí, pero en general es más seguro de usar.Para cosas como esta, prefiero generar SQL dinámico que pasar un solo comando a un procedimiento para ejecutar varias veces (incluso mi procedimiento, en el que confío mucho más), de esta manera simplemente puedo imprimir los comandos en lugar de ejecutarlos, y asegúrese de que todos hagan lo que dicen.
Partiendo de la observación de que el código subyacente a la vista del sistema implementa a
TOP (1)
, podemos intentar de esta manera:Tenga en cuenta que no uso
USE
aquí, sino que prefijo lasys
vista de catálogo con el nombre de la base de datos.Por qué la vista funciona de manera mágica, no lo sé; No sé si obtendrá una buena respuesta aquí, ya que es probable que requiera comentarios de Microsoft (o cualquier persona con acceso al código fuente o dispuesto a iniciar un depurador).
fuente
¡Gracias por informar este problema!
De hecho, esto es un error en la forma en que el Optimizador de consultas genera un plan para la
sys.database_scoped_configurations
vista de catálogo. Abordaremos esto en una de las próximas actualizaciones de SQL Server 2016 y en Azure SQL Database.Como solución alternativa, puede agregar una
TOP
cláusula en laSELECT
parte de su inserto para obtener el plan correcto, por ejemplo:fuente
Estoy de acuerdo en que esto es muy extraño y un error potencial, pero agregar un TOP (50), por ejemplo, a su selección en realidad devuelve todas las filas, por lo que eso al menos lo pondrá en marcha. El resultado parece provenir de una función de valor de tabla del sistema ([DB_SCOPED_CONFIG]), por lo que realmente no puedo decir qué está pasando.
Estaré atento a este hilo para ver si las personas 'más inteligentes' saben POR QUÉ esto está sucediendo.
fuente