J'apprends plus de détails dans la variable de table. Il dit que les tables temporaires sont toujours sur le disque et que les variables de table sont en mémoire, c'est-à-dire que les performances de la variable de table sont meilleures que celles de la table temporaire, car elles utilisent moins d'opérations IO que la table temporaire.
Mais parfois, s'il y a trop d'enregistrements dans une variable de table qui ne peuvent pas être contenus dans la mémoire, la variable de table sera placée sur le disque comme la table temporaire.
Mais je ne sais pas ce qu'est le "trop de disques". 100 000 enregistrements? ou 1000 000 enregistrements? Comment savoir si une variable de table que j'utilise est en mémoire ou sur disque? Existe-t-il une fonction ou un outil dans SQL Server 2005 pour mesurer l’échelle de la variable de table ou pour me prévenir lorsque la variable de table est mise sur le disque à partir de la mémoire?
Votre question montre que vous avez cédé à certaines des idées fausses courantes sur les variables de table et les tables temporaires.
J'ai écrit ne réponse assez détaillée sur le site DBA en regardant les différences entre les deux types d'objet. Cela répond également à votre question sur le disque par rapport à la mémoire (je n’ai pas constaté de différence significative de comportement entre les deux).
En ce qui concerne la question dans le titre sur le moment où utiliser une variable de table par rapport à une table temporaire locale, vous n’avez pas toujours le choix. Dans les fonctions, par exemple, il est uniquement possible d’utiliser une variable de table et si vous avez besoin d’écrire sur la table dans une étendue enfant, alors seule une table #temp
fera l'affaire (les paramètres de valeur table autorisent en lecture seule). accès ).
Si vous avez le choix, voici quelques suggestions (même si la méthode la plus fiable consiste simplement à tester les deux avec votre charge de travail spécifique).
Si vous avez besoin d'un index qui ne peut pas être créé sur une variable de table, vous aurez bien sûr besoin d'une table #temporary
. Les détails de cette opération dépendent toutefois de la version. Pour SQL Server 2012 et ultérieur, les seuls index pouvant être créés sur des variables de table étaient ceux créés implicitement via une contrainte UNIQUE
ou PRIMARY KEY
. SQL Server 2014 a introduit la syntaxe d'index en ligne pour un sous-ensemble des options disponibles dans CREATE INDEX
. Cela a été étendu depuis pour autoriser les conditions d'index filtrées. Les index avec INCLUDE
- d colonnes ou les index de colonnes ne sont toujours pas possibles pour créer des variables de table.
Si vous souhaitez ajouter et supprimer de manière répétée un grand nombre de lignes de la table, utilisez une table #temporary
. Cela prend en charge TRUNCATE
(qui est plus efficace que DELETE
pour les grandes tables). De plus, les insertions suivantes suivant un TRUNCATE
peuvent avoir de meilleures performances que celles qui suivent un DELETE
comme illustré ici .
#temporary
. Cela prend en charge la création de statistiques qui permettent au plan d’être recompilé dynamiquement en fonction des données (bien que pour les tables temporaires mises en cache dans les procédures stockées le comportement de recompilation doit être compris séparément).SELECT
potentiellement coûteuse, envisagez l'utilisation d'une variable de table pour bloquer la possibilité d'utiliser un plan parallèle.#temp
au sein d'un utilisateur, les verrous de transaction peuvent être conservés plus longtemps que pour les variables de table (potentiellement jusqu'à la fin de la transaction par rapport à la fin de l'instruction, en fonction du type de verrouillage et du niveau d'isolation). le journal de transactions tempdb
jusqu'à la fin de la transaction utilisateur. Cela pourrait donc favoriser l'utilisation de variables de table.#temporary
. Bob Ward souligne dans sa tempdb
presentation que cela peut entraîner des conflits supplémentaires sur les tables système dans des conditions de simultanéité élevée. De plus, lorsque vous manipulez de petites quantités de données, cela peut avoir un effet ne différence mesurable sur les performances .Effets du partage d'un ensemble de lignes
DECLARE @T TABLE(id INT PRIMARY KEY, Flag BIT);
CREATE TABLE #T (id INT PRIMARY KEY, Flag BIT);
INSERT INTO @T
output inserted.* into #T
SELECT TOP 1000000 ROW_NUMBER() OVER (ORDER BY @@SPID), 0
FROM master..spt_values v1, master..spt_values v2
SET STATISTICS TIME ON
/*CPU time = 7016 ms, elapsed time = 7860 ms.*/
UPDATE @T SET Flag=1;
/*CPU time = 6234 ms, elapsed time = 7236 ms.*/
DELETE FROM @T
/* CPU time = 828 ms, elapsed time = 1120 ms.*/
UPDATE #T SET Flag=1;
/*CPU time = 672 ms, elapsed time = 980 ms.*/
DELETE FROM #T
DROP TABLE #T
Utilisez une variable de table si, pour une très petite quantité de données (milliers d'octets)
Utiliser une table temporaire pour beaucoup de données
Une autre façon de penser: si vous pensez pouvoir tirer parti d’un index, de statistiques automatisées ou de tout avantage de l’optimiseur SQL, votre ensemble de données est probablement trop volumineux pour une variable de table.
Dans mon exemple, je voulais simplement mettre environ 20 lignes dans un format et les modifier en tant que groupe avant de les utiliser pour mettre à jour/insérer une table permanente. Donc, une variable de table est parfaite.
Mais j'utilise aussi SQL pour remplir de manière aléatoire des milliers de lignes à la fois, et je peux certainement affirmer que les tables temporaires fonctionnent beaucoup mieux que les variables de table.
Ce n'est pas sans rappeler à quel point les ETC sont une source d'inquiétude pour une raison de taille similaire: si les données contenues dans l'ECU sont très petites, je constate qu'un CTE donne des résultats aussi bons, voire meilleurs, que ce que l'optimiseur propose, mais s'il est assez volumineux, ça vous fait mal.
Ma compréhension est principalement basée sur http://www.developerfusion.com/article/84397/table-variables-v-temporary-tables-in-sql-server/ , qui contient beaucoup plus de détails. .
Microsoft dit ici
Les variables de table n'ont pas de statistiques de distribution, elles ne déclencheront pas de recompilation. Par conséquent, dans de nombreux cas, l'optimiseur construira un plan de requête en supposant que la variable de table ne comporte aucune ligne. Pour cette raison, vous devez être prudent avec l'utilisation d'une variable de table si vous vous attendez à un plus grand nombre de lignes (supérieur à 100). Les tables temporaires peuvent être une meilleure solution dans ce cas.
Je suis totalement d'accord avec Abacus (désolé - je n'ai pas assez de points pour commenter).
Aussi, gardez à l'esprit qu'il ne s'agit pas nécessairement de combien enregistrements que vous avez, mais du taille de vos enregistrements.
Par exemple, avez-vous pris en compte la différence de performance entre 1 000 enregistrements de 50 colonnes chacun contre 100 000 enregistrements de 5 colonnes chacun?
Enfin, peut-être interrogez-vous/stockez-vous plus de données que nécessaire? Voici une bonne lecture sur stratégies d'optimisation SQL . Limitez la quantité de données que vous extrayez, en particulier si vous n'utilisez pas tout cela (certains programmeurs SQL deviennent paresseux et sélectionnent tout, même s'ils n'utilisent qu'un tout petit sous-ensemble). N'oubliez pas que l'analyseur de requête SQL peut également devenir votre meilleur ami.
Table de variables n'est disponible que pour la session en cours. Par exemple, si vous devez EXEC
une autre procédure stockée dans la procédure actuelle, vous devrez transmettre la table sous la forme Table Valued Parameter
et bien sûr, cela affectera les performances, avec tables temporaires vous pouvez le faire en ne transmettant que le nom de la table temporaire
Pour tester une table temporaire:
Pour tester une table de variables:
une autre chose que j'ai expérimentée est la suivante: si votre schéma n'a pas le privilège GRANT
de créer des tables, utilisez des tables de variables.
écrire des données dans des tables déclarées declare @tb
et après avoir rejoint d’autres tables, je me suis rendu compte que le temps de réponse par rapport aux tables temporaires tempdb .. # tb
était beaucoup plus élevé.
Lorsque je les rejoins avec @ tb, le temps est beaucoup plus long pour renvoyer le résultat, contrairement à # tm, le retour est presque instantané.
J'ai fait des tests avec une jointure de 10 000 lignes et avec 5 autres tables