lectures logiques sur la table temporaire globale, mais pas sur la table temporaire au niveau de la session

11

Considérez le MCVE simple suivant:

SET STATISTICS IO, TIME OFF;
USE tempdb;

IF OBJECT_ID(N'tempdb..#t1', N'U') IS NOT NULL DROP TABLE #t1;
CREATE TABLE #t1
(
    r int NOT NULL
);

IF OBJECT_ID(N'tempdb..##t1', N'U') IS NOT NULL DROP TABLE ##t1;
CREATE TABLE ##t1
(
    r int NOT NULL
);

IF OBJECT_ID(N'dbo.s1', N'U') IS NOT NULL DROP TABLE dbo.s1;
CREATE TABLE dbo.s1 
(
    r int NOT NULL
        PRIMARY KEY CLUSTERED
);

INSERT INTO dbo.s1 (r)
SELECT TOP(10000) ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM sys.syscolumns sc1
    CROSS JOIN sys.syscolumns sc2;
GO

Lorsque j'exécute les insertions suivantes, l'insertion dans #t1ne montre aucune entrée / sortie de statistiques pour la table temporaire. Cependant, l' insertion dans le ##t1 fait Voir les statistiques d' E / S pour la table temporaire.

SET STATISTICS IO, TIME ON;
GO

INSERT INTO #t1 (r)
SELECT r
FROM dbo.s1;

La sortie des statistiques:

Temps d'analyse et de compilation de SQL Server: 
   Temps CPU = 0 ms, temps écoulé = 1 ms.
Tableau 's1'. Nombre de balayages 1, lectures logiques 19, lectures physiques 0, lectures anticipées 0, lectures logiques 0, lob lectures physiques 0, lob lectures anticipées 0.

 Temps d'exécution de SQL Server:
   Temps CPU = 16 ms, temps écoulé = 9 ms.

(10000 lignes affectées)
INSERT INTO ##t1 (r)
SELECT r
FROM dbo.s1;
Temps d'analyse et de compilation de SQL Server: 
   Temps CPU = 0 ms, temps écoulé = 1 ms.
Tableau '## t1'. Nombre de balayages 0, lectures logiques 10016, lectures physiques 0, lectures anticipées 0, lectures logiques 0, lob lectures physiques 0, lob lectures anticipées 0.
Tableau 's1'. Nombre de balayages 1, lectures logiques 19, lectures physiques 0, lectures anticipées 0, lectures logiques 0, lob lectures physiques 0, lob lectures anticipées 0.

 Temps d'exécution de SQL Server:
   Temps CPU = 47 ms, temps écoulé = 45 ms.

(10000 lignes affectées)

Pourquoi y a-t-il autant de lectures sur la table ## temp alors que je ne fais que l'insérer?

Max Vernon
la source

Réponses:

11

La journalisation minimale n'est pas utilisée lors de l'utilisation INSERT INTOdes tables temporaires et globales

Insertion d'un million de lignes dans une table temporaire globale à l'aide de INSERT INTO

INSERT INTO ##t1 (r)
SELECT top(1000000) s1.r
FROM dbo.s1
CROSS APPLY  dbo.s1 S2;

Lors de l'exécution SELECT * FROM fn_dblog(NULL, NULL)pendant l' exécution de la requête ci-dessus, ~ 1 million de lignes sont renvoyées.

entrez la description de l'image ici

Une LOP_INSERT_ROWopération pour chaque ligne + autres données de journal.


Le même insert sur une table temporaire locale

INSERT INTO #t1 (r)
SELECT top(1000000) s1.r
FROM dbo.s1
CROSS APPLY  dbo.s1 S2;

Jusqu'à 700 lignes renvoyées par SELECT * FROM fn_dblog(NULL, NULL)

entrez la description de l'image ici

Journalisation minimale


Insertion d'un million de lignes dans une table temporaire globale à l'aide de SELECT INTO

SELECT top(1000000) s1.r
INTO ##t2
FROM dbo.s1
CROSS APPLY  dbo.s1 S2;

entrez la description de l'image ici

SELECT INTO une table temp globale avec 10k enregistrements

SELECT s1.r
INTO ##t2
FROM dbo.s1;

Statistiques de temps et d'E / S

SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.
Table 's1'. Scan count 1, logical reads 19, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

 SQL Server Execution Times:
   CPU time = 16 ms,  elapsed time = 10 ms.
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 0 ms.

Sur la base de ce blog, nous pouvons ajouter TABLOCKpour lancer une journalisation minimale sur une table de tas

INSERT INTO ##t1 WITH(TABLOCK) (r)
SELECT   s1.r
FROM dbo.s1

Lectures logiques faibles

Table 's1'. Scan count 1, logical reads 19, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(10000 rows affected)

Partie d' une réponse de @PaulWhite sur la façon d'obtenir une journalisation minimale sur les tables temporaires

Non. Les tables temporaires locales (#temp) sont privées pour la session de création, donc un conseil de verrouillage de table n'est pas requis. Une indication de verrouillage de table serait requise pour une table temporaire globale (## temp) ou une table régulière (dbo.temp) créée dans tempdb, car elles sont accessibles à partir de plusieurs sessions.

Création d'une table régulière pour tester cela:

CREATE TABLE dbo.bla
(
    r int NOT NULL 
);

Le remplir avec 1 million d'enregistrements

INSERT INTO bla 
SELECT   top(1000000)s1.r
FROM dbo.s1
CROSS APPLY  dbo.s1 S2;

> 1 M de lectures logiques sur ce tableau

Table 's1'. Scan count 17, logical reads 155, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'bla'. Scan count 0, logical reads 1001607, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

Réponse de Paul White expliquant les lectures logiques reportées sur la table de temp globale

Généralement, les lectures logiques sont signalées pour la table cible lorsque l'insertion n'est pas journalisée de façon minimale.

Ces lectures logiques sont associées à la recherche d'une place dans la structure existante pour ajouter les nouvelles lignes. Les insertions à journalisation minimale utilisent le mécanisme de chargement en bloc, qui alloue de nouvelles pages / extensions entières (et n'a donc pas besoin de lire la structure cible de la même manière).


Conclusion

La conclusion étant que le INSERT INTOn'est pas en mesure d'utiliser une journalisation minimale, ce qui entraîne la journalisation de chaque ligne insérée individuellement dans le fichier journal de tempdb lorsqu'il est utilisé en combinaison avec une table temporaire globale / table normale. Alors que la table temporaire locale / SELECT INTO/ INSERT INTO ... WITH(TABLOCK)est capable d'utiliser une journalisation minimale.

Randi Vertongen
la source