Quelle est la différence entre une table temporaire et une variable de table dans SQL Server ?

StackOverflow https://stackoverflow.com/questions/27894

Question

Dans SQL Server 2005, nous pouvons créer des tables temporaires de deux manières :

declare @tmp table (Col1 int, Col2 int);

ou

create table #tmp (Col1 int, Col2 int);

Quelles sont les différences entre ces deux ?J'ai lu des opinions contradictoires sur la question de savoir si @tmp utilise toujours tempdb ou si tout se passe en mémoire.

Dans quels scénarios l’un surpasse-t-il l’autre ?

Était-ce utile?

La solution

Il existe quelques différences entre les tables temporaires (#tmp) et les variables de table (@tmp), bien que l'utilisation de tempdb n'en fasse pas partie, comme indiqué dans le lien MSDN ci-dessous.

En règle générale, pour des volumes de données petits à moyens et des scénarios d'utilisation simples, vous devez utiliser des variables de table.(Il s'agit d'une directive trop générale avec bien sûr de nombreuses exceptions - voir les articles ci-dessous et suivants.)

Quelques points à considérer lors du choix entre eux :

  • Les tables temporaires sont de vraies tables, vous pouvez donc faire des choses comme CREATE INDEX, etc.Si vous disposez de grandes quantités de données pour lesquelles l’accès par index sera plus rapide, les tables temporaires sont une bonne option.

  • Les variables de table peuvent avoir des index en utilisant des contraintes PRIMARY KEY ou UNIQUE.(Si vous souhaitez un index non unique, incluez simplement la colonne de clé primaire comme dernière colonne de la contrainte d'unicité.Si vous n'avez pas de colonne unique, vous pouvez utiliser une colonne d'identité.) SQL 2014 a également des index non uniques.

  • Les variables de table ne participent pas aux transactions et SELECTs sont implicitement avec NOLOCK.Le comportement de la transaction peut être très utile, par exemple si vous souhaitez effectuer un ROLLBACK à mi-chemin d'une procédure, les variables de table renseignées au cours de cette transaction le seront toujours !

  • Les tables temporaires peuvent entraîner la recompilation des procédures stockées, peut-être souvent.Les variables de table ne le seront pas.

  • Vous pouvez créer une table temporaire à l'aide de SELECT INTO, qui peut être plus rapide à écrire (idéale pour les requêtes ad hoc) et peut vous permettre de gérer l'évolution des types de données au fil du temps, car vous n'avez pas besoin de définir la structure de votre table temporaire à l'avance.

  • Vous pouvez renvoyer des variables de table à partir de fonctions, ce qui vous permet d'encapsuler et de réutiliser la logique beaucoup plus facilement (par exemple, créer une fonction pour diviser une chaîne en une table de valeurs sur un délimiteur arbitraire).

  • L'utilisation de variables de table dans des fonctions définies par l'utilisateur permet à ces fonctions d'être utilisées plus largement (voir la documentation CREATE FUNCTION pour plus de détails).Si vous écrivez une fonction, vous devez utiliser des variables de table sur des tables temporaires, sauf nécessité impérieuse.

  • Les variables de table et les tables temporaires sont stockées dans tempdb.Mais les variables de table (depuis 2005) utilisent par défaut le classement de la base de données actuelle par rapport aux tables temporaires qui prennent le classement par défaut de tempdb (réf).Cela signifie que vous devez être conscient des problèmes de classement si vous utilisez des tables temporaires et que le classement de votre base de données est différent de celui de tempdb, ce qui pose des problèmes si vous souhaitez comparer les données de la table temporaire avec les données de votre base de données.

  • Les tables temporaires globales (##tmp) sont un autre type de table temporaire disponible pour toutes les sessions et tous les utilisateurs.

Quelques lectures complémentaires :

Autres conseils

Il suffit de regarder l'affirmation dans la réponse acceptée selon laquelle les variables de table ne participent pas à la journalisation.

Il semble généralement faux qu'il existe une différence dans la quantité d'exploitation forestière (du moins pour insert/update/delete opérations à la table elle-même même si j'ai trouvé depuis qu'il existe une petite différence à cet égard pour les objets temporaires mis en cache dans les procédures stockées en raison de mises à jour supplémentaires des tables système).

J'ai examiné le comportement de journalisation à la fois par rapport à un @table_variable et un #temp tableau pour les opérations suivantes.

  1. Insertion réussie
  2. Insérer plusieurs lignes où l'instruction a été annulée en raison d'une violation de contrainte.
  3. Mise à jour
  4. Supprimer
  5. Désallouer

Les enregistrements du journal des transactions étaient presque identiques pour toutes les opérations.

La version variable de table en contient en fait quelques-unes supplémentaire entrées de journal car il obtient une entrée ajoutée (et ensuite supprimée) du sys.syssingleobjrefs table de base, mais dans l'ensemble, il y avait quelques octets de moins enregistrés simplement car le nom interne des variables de table consomme 236 octets de moins que pour #temp tables (118 de moins nvarchar personnages).

Script complet à reproduire (mieux exécuté sur une instance démarrée en mode mono-utilisateur et utilisant sqlcmd mode)

:setvar tablename "@T" 
:setvar tablescript "DECLARE @T TABLE"

/*
 --Uncomment this section to test a #temp table
:setvar tablename "#T" 
:setvar tablescript "CREATE TABLE #T"
*/

USE tempdb 
GO    
CHECKPOINT

DECLARE @LSN NVARCHAR(25)

SELECT @LSN = MAX([Current LSN])
FROM fn_dblog(null, null) 


EXEC(N'BEGIN TRAN StartBatch
SAVE TRAN StartBatch
COMMIT

$(tablescript)
(
[4CA996AC-C7E1-48B5-B48A-E721E7A435F0] INT PRIMARY KEY DEFAULT 0,
InRowFiller char(7000) DEFAULT ''A'',
OffRowFiller varchar(8000) DEFAULT REPLICATE(''B'',8000),
LOBFiller varchar(max) DEFAULT REPLICATE(cast(''C'' as varchar(max)),10000)
)


BEGIN TRAN InsertFirstRow
SAVE TRAN InsertFirstRow
COMMIT

INSERT INTO $(tablename)
DEFAULT VALUES

BEGIN TRAN Insert9Rows
SAVE TRAN Insert9Rows
COMMIT


INSERT INTO $(tablename) ([4CA996AC-C7E1-48B5-B48A-E721E7A435F0])
SELECT TOP 9 ROW_NUMBER() OVER (ORDER BY (SELECT 0))
FROM sys.all_columns

BEGIN TRAN InsertFailure
SAVE TRAN InsertFailure
COMMIT


/*Try and Insert 10 rows, the 10th one will cause a constraint violation*/
BEGIN TRY
INSERT INTO $(tablename) ([4CA996AC-C7E1-48B5-B48A-E721E7A435F0])
SELECT TOP (10) (10 + ROW_NUMBER() OVER (ORDER BY (SELECT 0))) % 20
FROM sys.all_columns
END TRY
BEGIN CATCH
PRINT ERROR_MESSAGE()
END CATCH

BEGIN TRAN Update10Rows
SAVE TRAN Update10Rows
COMMIT

UPDATE $(tablename)
SET InRowFiller = LOWER(InRowFiller),
    OffRowFiller  =LOWER(OffRowFiller),
    LOBFiller  =LOWER(LOBFiller)


BEGIN TRAN Delete10Rows
SAVE TRAN Delete10Rows
COMMIT

DELETE FROM  $(tablename)
BEGIN TRAN AfterDelete
SAVE TRAN AfterDelete
COMMIT

BEGIN TRAN EndBatch
SAVE TRAN EndBatch
COMMIT')


DECLARE @LSN_HEX NVARCHAR(25) = 
        CAST(CAST(CONVERT(varbinary,SUBSTRING(@LSN, 1, 8),2) AS INT) AS VARCHAR) + ':' +
        CAST(CAST(CONVERT(varbinary,SUBSTRING(@LSN, 10, 8),2) AS INT) AS VARCHAR) + ':' +
        CAST(CAST(CONVERT(varbinary,SUBSTRING(@LSN, 19, 4),2) AS INT) AS VARCHAR)        

SELECT 
    [Operation],
    [Context],
    [AllocUnitName],
    [Transaction Name],
    [Description]
FROM   fn_dblog(@LSN_HEX, null) AS D
WHERE  [Current LSN] > @LSN  

SELECT CASE
         WHEN GROUPING(Operation) = 1 THEN 'Total'
         ELSE Operation
       END AS Operation,
       Context,
       AllocUnitName,
       COALESCE(SUM([Log Record Length]), 0) AS [Size in Bytes],
       COUNT(*)                              AS Cnt
FROM   fn_dblog(@LSN_HEX, null) AS D
WHERE  [Current LSN] > @LSN  
GROUP BY GROUPING SETS((Operation, Context, AllocUnitName),())

Résultats

+-----------------------+--------------------+---------------------------+---------------+------+---------------+------+------------------+
|                       |                    |                           |             @TV      |             #TV      |                  |
+-----------------------+--------------------+---------------------------+---------------+------+---------------+------+------------------+
| Operation             | Context            | AllocUnitName             | Size in Bytes | Cnt  | Size in Bytes | Cnt  | Difference Bytes |
+-----------------------+--------------------+---------------------------+---------------+------+---------------+------+------------------+
| LOP_ABORT_XACT        | LCX_NULL           |                           | 52            | 1    | 52            | 1    |                  |
| LOP_BEGIN_XACT        | LCX_NULL           |                           | 6056          | 50   | 6056          | 50   |                  |
| LOP_COMMIT_XACT       | LCX_NULL           |                           | 2548          | 49   | 2548          | 49   |                  |
| LOP_COUNT_DELTA       | LCX_CLUSTERED      | sys.sysallocunits.clust   | 624           | 3    | 624           | 3    |                  |
| LOP_COUNT_DELTA       | LCX_CLUSTERED      | sys.sysrowsets.clust      | 208           | 1    | 208           | 1    |                  |
| LOP_COUNT_DELTA       | LCX_CLUSTERED      | sys.sysrscols.clst        | 832           | 4    | 832           | 4    |                  |
| LOP_CREATE_ALLOCCHAIN | LCX_NULL           |                           | 120           | 3    | 120           | 3    |                  |
| LOP_DELETE_ROWS       | LCX_INDEX_INTERIOR | Unknown Alloc Unit        | 720           | 9    | 720           | 9    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysallocunits.clust   | 444           | 3    | 444           | 3    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysallocunits.nc      | 276           | 3    | 276           | 3    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.syscolpars.clst       | 628           | 4    | 628           | 4    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.syscolpars.nc         | 484           | 4    | 484           | 4    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysidxstats.clst      | 176           | 1    | 176           | 1    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysidxstats.nc        | 144           | 1    | 144           | 1    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysiscols.clst        | 100           | 1    | 100           | 1    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysiscols.nc1         | 88            | 1    | 88            | 1    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysobjvalues.clst     | 596           | 5    | 596           | 5    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysrowsets.clust      | 132           | 1    | 132           | 1    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysrscols.clst        | 528           | 4    | 528           | 4    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysschobjs.clst       | 1040          | 6    | 1276          | 6    | 236              |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysschobjs.nc1        | 820           | 6    | 1060          | 6    | 240              |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysschobjs.nc2        | 820           | 6    | 1060          | 6    | 240              |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.sysschobjs.nc3        | 480           | 6    | 480           | 6    |                  |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.syssingleobjrefs.clst | 96            | 1    |               |      | -96              |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | sys.syssingleobjrefs.nc1  | 88            | 1    |               |      | -88              |
| LOP_DELETE_ROWS       | LCX_MARK_AS_GHOST  | Unknown Alloc Unit        | 72092         | 19   | 72092         | 19   |                  |
| LOP_DELETE_ROWS       | LCX_TEXT_MIX       | Unknown Alloc Unit        | 16348         | 37   | 16348         | 37   |                  |
| LOP_FORMAT_PAGE       | LCX_HEAP           | Unknown Alloc Unit        | 1596          | 19   | 1596          | 19   |                  |
| LOP_FORMAT_PAGE       | LCX_IAM            | Unknown Alloc Unit        | 252           | 3    | 252           | 3    |                  |
| LOP_FORMAT_PAGE       | LCX_INDEX_INTERIOR | Unknown Alloc Unit        | 84            | 1    | 84            | 1    |                  |
| LOP_FORMAT_PAGE       | LCX_TEXT_MIX       | Unknown Alloc Unit        | 4788          | 57   | 4788          | 57   |                  |
| LOP_HOBT_DDL          | LCX_NULL           |                           | 108           | 3    | 108           | 3    |                  |
| LOP_HOBT_DELTA        | LCX_NULL           |                           | 9600          | 150  | 9600          | 150  |                  |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | sys.sysallocunits.clust   | 456           | 3    | 456           | 3    |                  |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | sys.syscolpars.clst       | 644           | 4    | 644           | 4    |                  |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | sys.sysidxstats.clst      | 180           | 1    | 180           | 1    |                  |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | sys.sysiscols.clst        | 104           | 1    | 104           | 1    |                  |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | sys.sysobjvalues.clst     | 616           | 5    | 616           | 5    |                  |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | sys.sysrowsets.clust      | 136           | 1    | 136           | 1    |                  |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | sys.sysrscols.clst        | 544           | 4    | 544           | 4    |                  |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | sys.sysschobjs.clst       | 1064          | 6    | 1300          | 6    | 236              |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | sys.syssingleobjrefs.clst | 100           | 1    |               |      | -100             |
| LOP_INSERT_ROWS       | LCX_CLUSTERED      | Unknown Alloc Unit        | 135888        | 19   | 135888        | 19   |                  |
| LOP_INSERT_ROWS       | LCX_INDEX_INTERIOR | Unknown Alloc Unit        | 1596          | 19   | 1596          | 19   |                  |
| LOP_INSERT_ROWS       | LCX_INDEX_LEAF     | sys.sysallocunits.nc      | 288           | 3    | 288           | 3    |                  |
| LOP_INSERT_ROWS       | LCX_INDEX_LEAF     | sys.syscolpars.nc         | 500           | 4    | 500           | 4    |                  |
| LOP_INSERT_ROWS       | LCX_INDEX_LEAF     | sys.sysidxstats.nc        | 148           | 1    | 148           | 1    |                  |
| LOP_INSERT_ROWS       | LCX_INDEX_LEAF     | sys.sysiscols.nc1         | 92            | 1    | 92            | 1    |                  |
| LOP_INSERT_ROWS       | LCX_INDEX_LEAF     | sys.sysschobjs.nc1        | 844           | 6    | 1084          | 6    | 240              |
| LOP_INSERT_ROWS       | LCX_INDEX_LEAF     | sys.sysschobjs.nc2        | 844           | 6    | 1084          | 6    | 240              |
| LOP_INSERT_ROWS       | LCX_INDEX_LEAF     | sys.sysschobjs.nc3        | 504           | 6    | 504           | 6    |                  |
| LOP_INSERT_ROWS       | LCX_INDEX_LEAF     | sys.syssingleobjrefs.nc1  | 92            | 1    |               |      | -92              |
| LOP_INSERT_ROWS       | LCX_TEXT_MIX       | Unknown Alloc Unit        | 5112          | 71   | 5112          | 71   |                  |
| LOP_MARK_SAVEPOINT    | LCX_NULL           |                           | 508           | 8    | 508           | 8    |                  |
| LOP_MODIFY_COLUMNS    | LCX_CLUSTERED      | Unknown Alloc Unit        | 1560          | 10   | 1560          | 10   |                  |
| LOP_MODIFY_HEADER     | LCX_HEAP           | Unknown Alloc Unit        | 3780          | 45   | 3780          | 45   |                  |
| LOP_MODIFY_ROW        | LCX_CLUSTERED      | sys.syscolpars.clst       | 384           | 4    | 384           | 4    |                  |
| LOP_MODIFY_ROW        | LCX_CLUSTERED      | sys.sysidxstats.clst      | 100           | 1    | 100           | 1    |                  |
| LOP_MODIFY_ROW        | LCX_CLUSTERED      | sys.sysrowsets.clust      | 92            | 1    | 92            | 1    |                  |
| LOP_MODIFY_ROW        | LCX_CLUSTERED      | sys.sysschobjs.clst       | 1144          | 13   | 1144          | 13   |                  |
| LOP_MODIFY_ROW        | LCX_IAM            | Unknown Alloc Unit        | 4224          | 48   | 4224          | 48   |                  |
| LOP_MODIFY_ROW        | LCX_PFS            | Unknown Alloc Unit        | 13632         | 169  | 13632         | 169  |                  |
| LOP_MODIFY_ROW        | LCX_TEXT_MIX       | Unknown Alloc Unit        | 108640        | 120  | 108640        | 120  |                  |
| LOP_ROOT_CHANGE       | LCX_CLUSTERED      | sys.sysallocunits.clust   | 960           | 10   | 960           | 10   |                  |
| LOP_SET_BITS          | LCX_GAM            | Unknown Alloc Unit        | 1200          | 20   | 1200          | 20   |                  |
| LOP_SET_BITS          | LCX_IAM            | Unknown Alloc Unit        | 1080          | 18   | 1080          | 18   |                  |
| LOP_SET_BITS          | LCX_SGAM           | Unknown Alloc Unit        | 120           | 2    | 120           | 2    |                  |
| LOP_SHRINK_NOOP       | LCX_NULL           |                           |               |      | 32            | 1    | 32               |
+-----------------------+--------------------+---------------------------+---------------+------+---------------+------+------------------+
| Total                 |                    |                           | 410144        | 1095 | 411232        | 1092 | 1088             |
+-----------------------+--------------------+---------------------------+---------------+------+---------------+------+------------------+

Dans quels scénarios l’un surpasse-t-il l’autre ?

Pour les tables plus petites (moins de 1 000 lignes), utilisez une variable temporaire, sinon utilisez une table temporaire.

@wcm - en fait, pour choisir, la variable de table n'est pas uniquement de la RAM - elle peut être partiellement stockée sur le disque.

Une table temporaire peut avoir des index, alors qu'une variable de table ne peut avoir qu'un index principal.Si la vitesse est un problème, les variables de table peuvent être plus rapides, mais évidemment s'il y a beaucoup d'enregistrements ou s'il est nécessaire de rechercher la table temporaire d'un index clusterisé, une table temporaire serait alors préférable.

Bon article de fond

  1. Tableau temporaire :Une table temporaire est facile à créer et à sauvegarder des données.

    Variable du tableau :Mais la variable table implique des efforts lorsque nous créons habituellement les tables normales.

  2. Tableau temporaire :Le résultat de la table temporaire peut être utilisé par plusieurs utilisateurs.

    Variable du tableau :Mais la variable table ne peut être utilisée que par l’utilisateur actuel.

  3. Tableau temporaire :La table temporaire sera stockée dans la base de données tempdb.Cela créera du trafic réseau.Lorsque nous avons des données volumineuses dans la table temporaire, elles doivent fonctionner dans toute la base de données.Un problème de performances existera.

    Variable du tableau :Mais une variable de table stockera dans la mémoire physique une partie des données, puis plus tard, lorsque la taille augmentera, elle sera déplacée vers la base de données tempdb.

  4. Tableau temporaire :La table temporaire peut effectuer toutes les opérations DDL.Il permet de créer les index, de les supprimer, de les modifier, etc.,

    Variable du tableau :Alors que la variable de table ne permettra pas d'effectuer les opérations DDL.Mais la variable table nous permet de créer uniquement l'index clusterisé.

  5. Tableau temporaire :La table temporaire peut être utilisée pour la session en cours ou globale.Pour qu'une session multi-utilisateurs puisse utiliser les résultats du tableau.

    Variable du tableau :Mais la variable table peut être utilisée jusqu'à ce programme.(Procédure stockée)

  6. Tableau temporaire :La variable temporaire ne peut pas utiliser les transactions.Lorsque nous effectuons les opérations DML avec la table temporaire, il peut s'agir d'une restauration ou d'une validation des transactions.

    Variable du tableau :Mais nous ne pouvons pas le faire pour une variable de table.

  7. Tableau temporaire :Les fonctions ne peuvent pas utiliser la variable temp.De plus nous ne pouvons pas faire l'opération DML dans les fonctions.

    Variable du tableau :Mais la fonction nous permet d'utiliser la variable table.Mais en utilisant la variable table, nous pouvons le faire.

  8. Tableau temporaire :La procédure stockée effectuera la recompilation (ne peut pas utiliser le même plan d'exécution) lorsque nous utiliserons la variable temporaire pour chaque appel ultérieur.

    Variable du tableau :Alors que la variable table ne fera pas comme ça.

Pour tous ceux d'entre vous qui croient au mythe selon lequel les variables temporaires sont uniquement en mémoire

Premièrement, la variable de table n’est PAS nécessairement résidente en mémoire.Sous pression de mémoire, les pages appartenant à une variable de table peuvent être poussées vers tempdb.

Lire l'article ici : TempDB : Variable de table vs table temporaire locale

L'autre différence principale est que les variables de table n'ont pas de statistiques de colonne, contrairement aux tables temporaires.Cela signifie que l'optimiseur de requêtes ne sait pas combien de lignes se trouvent dans la variable de table (il en devine 1), ce qui peut conduire à la génération de plans très non optimaux si la variable de table comporte en réalité un grand nombre de lignes.

Citation tirée de ; Fonctions internes et dépannage de Professional SQL Server 2012

Statistiques La principale différence entre les tables temporaires et les variables de table est que Les statistiques ne sont pas créées sur les variables de table.Il y a deux grandes raisons conséquences, dont la première est que l’optimiseur de requête utilise un Estimation fi xée du nombre de lignes d’une variable de table quelles que soient les données qu’il contient.De plus, l’ajout ou la suppression de Les données ne modifient pas l’estimation.

Index Vous ne pouvez pas créer d’index sur des variables de table, bien que vous puissiez créer des contraintes.Cela signifie qu’en créant des clés primaires ou des clés uniques contraintes, vous pouvez avoir des index (car ceux-ci sont créés pour prendre en charge contraintes) sur les variables de table.Même si vous avez des contraintes, et par conséquent, les index qui auront des statistiques, les index ne seront pas utilisés lorsque la requête est compilée, car ils n’existeront pas lors de la compilation temps, et ils ne provoqueront pas non plus de recompilations.

Modifications du schéma Des modifications de schéma sont possibles sur les mais pas sur les variables de table.Bien que les modifications de schéma soient possible sur les tables temporaires, évitez de les utiliser car elles recompilations d’instructions qui utilisent les tables.

Temporary Tables versus Table Variables

LES VARIABLES DE TABLE NE SONT PAS CRÉÉES EN MÉMOIRE

On pense souvent à tort que les variables de table sont des structures en mémoire et, en tant que telle, fonctionnera plus rapidement que les tables temporaires.Grâce à un DMV appelé sys .dm _ db _ session _ space _ usage , qui montre l’utilisation de tempdb par session tu peux prouver que ce n'est pas le cas.Après avoir redémarré SQL Server pour effacer le DMV, exécutez le script suivant pour confirmer que votre _ id de session renvoie 0 pour utilisateur _ objets _ alloc _ page _ nombre :

SELECT session_id,
database_id,
user_objects_alloc_page_count
FROM sys.dm_db_session_space_usage
WHERE session_id > 50 ;

Vous pouvez maintenant vérifier la quantité d’espace utilisée par une table temporaire en exécutant la commande suivante script pour créer une table temporaire avec une colonne et la remplir avec une ligne :

CREATE TABLE #TempTable ( ID INT ) ;
INSERT INTO #TempTable ( ID )
VALUES ( 1 ) ;
GO
SELECT session_id,
database_id,
user_objects_alloc_page_count
FROM sys.dm_db_session_space_usage
WHERE session_id > 50 ;

Les résultats sur mon serveur indiquent qu'une page a été allouée à la table dans tempdb.Exécutez maintenant le même script mais utilisez une variable de table Cette heure:

DECLARE @TempTable TABLE ( ID INT ) ;
INSERT INTO @TempTable ( ID )
VALUES ( 1 ) ;
GO
SELECT session_id,
database_id,
user_objects_alloc_page_count
FROM sys.dm_db_session_space_usage
WHERE session_id > 50 ;

Lequel utiliser ?

Que vous utilisiez ou non des tables temporaires ou des variables de table doit être décidée par des tests approfondis, mais il est préférable d'opter pour du temporaire tables par défaut car il y a beaucoup moins de choses qui peuvent aller faux.

J’ai vu des clients développer du code à l’aide de variables de table parce qu’ils s’occupaient d’un petit nombre de lignes, et c’était plus rapide qu’un temporaire, mais quelques années plus tard, il y avait des centaines de des milliers de lignes dans la variable de table et les performances étaient terribles, Essayez donc de prévoir une certaine planification de la capacité lorsque vous décision!

Autre différence :

Une table var n'est accessible qu'à partir des instructions de la procédure qui la crée, et non à partir d'autres procédures appelées par cette procédure ou du SQL dynamique imbriqué (via exec ou sp_executesql).

En revanche, la portée d'une table temporaire inclut le code des procédures appelées et du SQL dynamique imbriqué.

Si la table créée par votre procédure doit être accessible depuis d'autres procédures appelées ou depuis du SQL dynamique, vous devez utiliser une table temporaire.Cela peut s’avérer très utile dans des situations complexes.

Considérez également que vous pouvez souvent remplacer les deux par des tables dérivées qui peuvent également être plus rapides.Cependant, comme pour tout réglage des performances, seuls des tests réels sur vos données réelles peuvent vous indiquer la meilleure approche pour votre requête particulière.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top