logis dibaca di tabel temp global, tetapi tidak pada tabel temp level-sesi

11

Pertimbangkan MCVE sederhana berikut ini:

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

Ketika saya menjalankan sisipan berikut, memasukkan ke #t1menunjukkan tidak ada statistik I / O untuk tabel temp. Namun, memasukkan ke ##t1 tidak menunjukkan statistik I / O untuk tabel temp.

SET STATISTICS IO, TIME ON;
GO

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

Output statistik:

SQL Server mengurai dan mengkompilasi waktu: 
   Waktu CPU = 0 ms, waktu yang berlalu = 1 ms.
Tabel 's1'. Pindai hitungan 1, bacaan logis 19, bacaan fisik 0, bacaan baca depan 0, bacaan logis lob 0, bacaan fisik lob 0, bacaan baca lob depan 0.

 Waktu Eksekusi SQL Server:
   Waktu CPU = 16 ms, waktu yang berlalu = 9 ms.

(10000 baris terpengaruh)
INSERT INTO ##t1 (r)
SELECT r
FROM dbo.s1;
SQL Server mengurai dan mengkompilasi waktu: 
   Waktu CPU = 0 ms, waktu yang berlalu = 1 ms.
Tabel '## t1'. Pindai hitungan 0, bacaan logis 10016, bacaan fisik 0, bacaan baca-depan 0, bacaan logis lob 0, bacaan fisik lob 0, bacaan baca lob depan 0.
Tabel 's1'. Pindai hitungan 1, bacaan logis 19, bacaan fisik 0, bacaan baca depan 0, bacaan logis lob 0, bacaan fisik lob 0, bacaan baca lob depan 0.

 Waktu Eksekusi SQL Server:
   Waktu CPU = 47 ms, waktu yang berlalu = 45 ms.

(10000 baris terpengaruh)

Mengapa ada begitu banyak bacaan di tabel temp ## ketika saya hanya memasukkan ke dalamnya?

Max Vernon
sumber

Jawaban:

11

Pencatatan minimum tidak digunakan saat menggunakan INSERT INTOdan tabel temp global

Memasukkan satu juta baris ke tabel temp global dengan menggunakan INSERT INTO

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

Saat berjalan SELECT * FROM fn_dblog(NULL, NULL)saat kueri di atas dieksekusi, ~ 1M baris dikembalikan.

masukkan deskripsi gambar di sini

Satu LOP_INSERT_ROWoperasi untuk setiap baris + data log lainnya.


Sisipan yang sama pada tabel temp lokal

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

Hanya naik hingga 700 baris yang dikembalikan oleh SELECT * FROM fn_dblog(NULL, NULL)

masukkan deskripsi gambar di sini

Minimal logging


Memasukkan satu juta baris ke tabel temp global dengan menggunakan SELECT INTO

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

masukkan deskripsi gambar di sini

SELECT INTO tabel temp global dengan catatan 10k

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

Statistik Waktu dan IO

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.

Berdasarkan blogpost ini kita dapat menambahkan TABLOCKuntuk memulai penebangan minimal pada tabel heap

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

Bacaan logis rendah

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)

Bagian dari jawaban oleh @PaulWhite tentang cara mencapai minimal logging di tabel sementara

Tidak. Tabel sementara lokal (#temp) bersifat pribadi untuk sesi pembuatan, jadi petunjuk kunci tabel tidak diperlukan. Petunjuk kunci tabel akan diperlukan untuk tabel sementara global (## temp) atau tabel biasa (dbo.temp) dibuat dalam tempdb, karena ini dapat diakses dari beberapa sesi.

Membuat tabel biasa untuk menguji ini:

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

Mengisinya dengan catatan 1 juta

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

> 1M dibaca logis pada tabel ini

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.

Jawaban Paul White menjelaskan bacaan logis yang dilaporkan pada tabel temp global

Secara umum, pembacaan logis dilaporkan untuk tabel target ketika sisipan tidak dicatat minimal.

Bacaan logis ini terkait dengan menemukan tempat di struktur yang ada untuk menambahkan baris baru. Sisipan yang dicatat secara minimum menggunakan mekanisme pemuatan massal, yang mengalokasikan seluruh halaman / luasan baru (dan karenanya tidak perlu membaca struktur target dengan cara yang sama).


Kesimpulan

Kesimpulannya adalah bahwa INSERT INTOtidak dapat menggunakan minimal logging, menghasilkan logging setiap baris yang dimasukkan secara individual dalam file log tempdb bila digunakan dalam kombinasi dengan tabel temp global / tabel normal. Sedangkan tabel temp lokal / SELECT INTO/ INSERT INTO ... WITH(TABLOCK)dapat menggunakan logging minimal.

Randi Vertongen
sumber