web-dev-qa-db-fra.com

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

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 #t1 n'affiche pas d'E/S de statistiques pour la table temporaire. Cependant, l'insertion dans ##t1fait affiche les E/S de statistiques 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 SQL Server: 
 Temps CPU = 0 ms, temps écoulé = 1 ms. 
 Table 's1'. Nombre de scans 1, lectures logiques 19, lectures physiques 0, lectures anticipées 0, lectures logiques 0, lob lectures physiques 0, lob lectures anticipées 0. 
 
 SQL Server Execution Times: 
 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 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 scans 1, lectures logiques 19, lectures physiques 0, lectures anticipées 0, lectures logiques 0, lob lectures physiques 0, lob lectures anticipées 0. 
 
 SQL Server Execution Times: 
 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?

11
Max Vernon

La journalisation minimale n'est pas utilisée lors de l'utilisation de INSERT INTO Et des tables temporaires globales

Insertion d'un million de lignes dans une table temporaire globale en utilisant INSERT INTO

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

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

enter image description here

Une opération LOP_INSERT_ROW 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 retournées par SELECT * FROM fn_dblog(NULL, NULL)

enter image description here

Journalisation minimale


Insertion d'un million de lignes dans une table temporaire globale en utilisant SELECT INTO

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

enter image description here

SELECT INTO Une table temporaire globale avec 10k enregistrements

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

Heure et IO Statistiques

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.

Basé sur cet article de blog nous pouvons ajouter TABLOCK pour initier 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)

Une partie de ne réponse par @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 
);

Remplir avec 1M 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.

Paul White réponse 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 INSERT INTO N'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. Tandis que la table temporaire locale/SELECT INTO/INSERT INTO ... WITH(TABLOCK) est capable d'utiliser une journalisation minimale.

11
Randi Vertongen