J'essaie d'insérer le jeu de résultats à partir de:
SELECT * FROM sys.database_scoped_configurations
dans une table temporaire, car je veux vérifier les paramètres de toutes les bases de données sur mon serveur. J'ai donc écrit ce code:
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
Mais alors, il n'y aura qu'une seule ligne par base de données, pas les quatre lignes que j'attends de l'exécution d'une sélection simple dans chaque base de données.
Je sais qu'il existe de meilleures façons de coder cela que d'utiliser sp_MSForEachDB, et j'en ai essayé plusieurs. Mais je n'ai toujours qu'une seule ligne par base de données. J'ai essayé cela sur SQL Server 2016 RTM et SP1
Est-ce un bogue avec SQL Server 2016, ou est-ce que je fais quelque chose de mal?
sql-server
configuration
sql-server-2016
Henrik Staun Poulsen
la source
la source
Réponses:
Oui. Ce n'est certainement pas un comportement correct. Je l'ai signalé ici et est résolu dans SQL Server 2016 SP2 CU9 .
Comme Mikael Eriksson le dit dans les commentaires
sys.database_scoped_configurations
etsys.dm_exec_sessions
sont mis en œuvre sous forme de vues au formatCependant, en comparant les deux plans ci-dessous, il y a une différence évidente.
L'indicateur de trace 8619 affiche la sortie de ces deux requêtes
SQL Server n'est apparemment pas en mesure de vérifier que la source du TVF n'est pas également la cible d'insertion, il nécessite donc une protection Halloween.
Dans le cas des sessions, cela a été implémenté comme un spool qui capture d'abord toutes les lignes. Dans le
database_scoped_configurations
en ajoutant unTOP 1
au plan. L'utilisation deTOP
pour la protection Halloween est discutée dans cet article . L'article mentionne également un indicateur de trace non documenté pour forcer une bobine plutôt queTOP
cela fonctionne comme prévu.Un problème évident avec l'utilisation
TOP 1
plutôt qu'avec une bobine est qu'elle limitera arbitrairement le nombre de lignes insérées. Ainsi, cela ne serait valide que si le nombre de lignes renvoyées par la fonction était <= 1.Le mémo initial ressemble à ceci
Comparez cela avec le mémo initial de la requête 2
Si je comprends bien ce qui précède, il pense que le premier TVF peut renvoyer un maximum d'une ligne et applique donc une optimisation incorrecte. Le Max pour la deuxième requête est défini sur
1.34078E+154
(2^512
).Je n'ai aucune idée d'où ce nombre maximal de lignes est dérivé. Peut-être des métadonnées fournies par l'auteur du DMV? Il est également étrange que la
TOP(50)
solution de contournement ne soit pas réécrite,TOP(1)
carTOP(50)
cela n'empêcherait pas le problème d'Halloween de se produire (mais l'empêcherait de continuer indéfiniment)la source
Veuillez cesser d'utiliser
sp_MSForEachDB
. Il n'est pas pris en charge, n'est pas documenté et est bogué - ce qui peut être le problème ici. Mon remplaçant présente le même problème ici, mais en général, c'est une chose plus sûre à utiliser.Pour des choses comme celle-ci, je préfère générer du SQL dynamique plutôt que de transmettre une seule commande à une procédure à exécuter plusieurs fois (même ma procédure, à laquelle j'ai beaucoup plus confiance), de cette façon je peux simplement imprimer les commandes au lieu de les exécuter, et assurez-vous qu'ils vont tous faire ce qu'ils disent.
En empruntant à l'observation que le code sous-jacent à la vue système implémente a
TOP (1)
, nous pouvons essayer de cette façon:Notez que je n'utilise pas
USE
ici, mais préfixez plutôt lasys
vue de catalogue avec le nom de la base de données.Pourquoi la vue fonctionne de façon magique, je ne sais pas; Je ne sais pas si vous obtiendrez une bonne réponse ici, car cela nécessite probablement des commentaires de Microsoft (ou de toute personne ayant accès au code source ou désireuse de lancer un débogueur).
la source
Merci d'avoir signalé ce problème!
Il s'agit en effet d'un bogue dans la façon dont l'Optimiseur de requête génère un plan pour la
sys.database_scoped_configurations
vue catalogue. Nous allons résoudre ce problème lors de l'une des prochaines mises à jour de SQL Server 2016 et dans Azure SQL Database.Comme solution de contournement, vous pouvez ajouter une
TOP
clause de laSELECT
part de votre insert pour obtenir le plan correct, par exemple:la source
Je suis d'accord que c'est très étrange et un bug potentiel, mais l'ajout d'un TOP (50), par exemple, à votre sélection retourne en fait toutes les lignes, ce qui vous permettrait au moins de continuer. Le résultat semble provenir d'une fonction de valeur de table système ([DB_SCOPED_CONFIG]), donc je ne peux pas vraiment dire ce qui se passe.
Je garderai un œil sur ce fil pour voir si les gens «plus intelligents» savent POURQUOI cela se produit.
la source