web-dev-qa-db-ja.com

グローバルレベルの一時テーブルではなく、セッションレベルの一時テーブルでの論理読み取り

次の単純なMCVEを考えてみます。

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

次の挿入を実行すると、#t1に挿入しても、一時テーブルの統計I/Oが表示されません。ただし、##t1doesに挿入すると、一時テーブルの統計I/Oが表示されます。

SET STATISTICS IO, TIME ON;
GO

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

統計出力:

SQL Serverの解析時間とコンパイル時間:
 CPU時間= 0ミリ秒、経過時間= 1ミリ秒。
テーブル 's1'。スキャンカウント1、論理読み取り19、物理読み取り0、先読み読み取り0、LOB論理読み取り0、LOB物理読み取り0、LOB先読み読み取り0。
 
 SQL Server実行時間: 
 CPU時間= 16ミリ秒、経過時間= 9ミリ秒。
 
(10000行に影響)
INSERT INTO ##t1 (r)
SELECT r
FROM dbo.s1;
SQL Serverの解析時間とコンパイル時間:
 CPU時間= 0ミリ秒、経過時間= 1ミリ秒。
表 '## t1'。スキャンカウント0、論理読み取り10016、物理読み取り0、先読み読み取り0、LOB論理読み取り0、LOB物理読み取り0、LOB先読み読み取り0。
テーブル 's1'。スキャンカウント1、論理読み取り19、物理読み取り0、先読み読み取り0、LOB論理読み取り0、LOB物理読み取り0、LOB先読み読み取り0。
 
 SQL Server実行時間: 
 CPU時間= 47ミリ秒、経過時間= 45ミリ秒。
 
(10000行に影響)

## tempテーブルに挿入しているだけなのに、なぜ## tempテーブルに非常に多くの読み取りがあるのですか?

11
Max Vernon

_INSERT INTO_およびグローバル一時テーブルを使用する場合、最小限のロギングは使用されません

_INSERT INTO_を使用して、グローバル一時テーブルに100万行を挿入する

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

上記のクエリの実行中にSELECT * FROM fn_dblog(NULL, NULL)を実行すると、約100万行が返されます。

enter image description here

行ごとに1つの_LOP_INSERT_ROW_操作+他のログデータ


ローカル一時テーブルへの同じ挿入

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

SELECT * FROM fn_dblog(NULL, NULL)によって返される行は最大700行まで

enter image description here

最小限のロギング


_SELECT INTO_を使用してグローバル一時テーブルに100万行を挿入する

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

enter image description here

_SELECT INTO_ 10kレコードのグローバル一時テーブル

_SELECT s1.r
INTO ##t2
FROM dbo.s1;
_

時間と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.
_

このブログ投稿 に基づいて、ヒープテーブルで最小限のロギングを開始するためにTABLOCKを追加できます

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

低論理読み取り

_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)
_

an answer の一部-@ PaulWhiteによる、一時テーブルでの最小限のロギングを実現する方法

いいえ。ローカル一時テーブル(#temp)は作成セッション専用なので、テーブルロックヒントは必要ありません。 tempdbで作成されたグローバル一時テーブル(## temp)または通常テーブル(dbo.temp)には、複数のセッションからアクセスできるため、テーブルロックヒントが必要です。

これをテストするための通常のテーブルの作成:

_CREATE TABLE dbo.bla
(
    r int NOT NULL 
);
_

100万レコードで埋めます

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

>このテーブルで100万回の論理読み取り

_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の answer グローバル一時テーブルで報告された論理読み取りの説明

一般に、挿入が最小限のログに記録されていない場合、論理読み取りはターゲットテーブルに対して報告されます。

これらの論理読み取りは、新しい行を追加するための既存の構造内の場所の検索に関連付けられています。最小限のログが記録された挿入では、新しいページ全体またはエクステント全体を割り当てる一括読み込みメカニズムを使用します(したがって、同じ方法でターゲット構造を読み取る必要はありません)。


結論

_INSERT INTO_は最小限のロギングを使用できないため、グローバル一時テーブル/通常テーブルと組み合わせて使用​​すると、挿入されたすべての行がtempdbのログファイルに個別にロギングされるという結論になります。一方、ローカル一時テーブル/ _SELECT INTO_/INSERT INTO ... WITH(TABLOCK)は、最小限のロギングを使用できます。

11
Randi Vertongen