Ok。これが私が実行しようとしているものです:
USE tempdb;
SELECT TOP 1000000 IDENTITY(INT, 1, 1) Number
INTO Numbers
FROM sys.objects s1
CROSS JOIN sys.objects s2
CROSS JOIN sys.objects s3
CROSS JOIN sys.objects s4;
これは、「数値表を作成する」クエリの 1 つです。
これが問題です。SQL Server サービスが (再) 開始された直後にこれを実行すると、永遠に時間がかかります。10秒のように永遠ではなく、もっと速くしたい. 永遠に、偶然に2時間以上放置したことがあり、それでも殺さなければなりませんでした。私はそれが二度と戻ってこないことを考えています。通常、私のマシンではこれを実行するのに 2 秒もかかりません。
ただし、代わりにこれを行うと:
USE tempdb;
SELECT TOP 1000000 IDENTITY(INT, 1, 1) Number
INTO Numbers
FROM sys.objects s1
CROSS JOIN sys.objects s2
CROSS JOIN sys.objects s3;
DROP TABLE Numbers;
SELECT TOP 1000000 IDENTITY(INT, 1, 1) Number
INTO Numbers
FROM sys.objects s1
CROSS JOIN sys.objects s2
CROSS JOIN sys.objects s3
CROSS JOIN sys.objects s4;
その後、期待どおりに動作します。最初のSELECT実行は 2 秒未満で実行され、2 番目の実行も同様です。3 テーブル バージョンを使用しないのはなぜですか? sys.objects100 万の結果行に等しくなるようにその数を 3 乗するのに十分なエントリがないためです。しかし、それはもはや重要なことではありません。
とにかく、ここからはその秒を繰り返しても構いませんDROP/SELECT…INTO好きなだけ、問題ありません。どういうわけか、その最初の 3 つのテーブルのバージョンは永遠に問題ありませんでした。少なくとも、次回サービスが再起動されるまで、および/またはマシンが再起動されるまで。その時点で、最後SELECTにもう一度実行すると、元に戻ることはありません。また。
ここからさらに奇妙になり始めます。最初SELECTに 2 つのテーブルのバージョンに戻すと、次のようになります。
USE tempdb;
SELECT TOP 1000000 IDENTITY(INT, 1, 1) Number
INTO Numbers
FROM sys.objects s1
CROSS JOIN sys.objects s2;
DROP TABLE Numbers;
SELECT TOP 1000000 IDENTITY(INT, 1, 1) Number
INTO Numbers
FROM sys.objects s1
CROSS JOIN sys.objects s2
CROSS JOIN sys.objects s3
CROSS JOIN sys.objects s4;
これにより、2回目のSELECT実行も永遠になります。 1 テーブル バージョンと同様です。どういうわけか、その 3 テーブル バージョンは魔法のようです!
ここで何が起こっているのですか?なぜこれが遅いのですか?
(そして、私が で永続的なテーブルを作成していると誰かが指摘する前にtempdb、はい、知っています。実際の一時テーブルに変更しても違いはありません。)
追加情報:
- これは SQL Server 2012 開発者版です
EXEC sp_WhoIsActive @find_block_leaders = 1, @sort_order = '[blocked_session_count] DESC'(XMLとしてスクリプト化されているため、ここで読むことができます)の出力は次のとおりです。
<?xml バージョン="1.0" ?>
<結果1>
<記録>
<dd hh:mm:ss.mss>00 00:10:45.066</dd hh:mm:ss.mss>
<session_id>52</session_id>
<sql_text><?クエリ --
SELECT TOP 1000000 IDENTITY(INT, 1, 1) 数値
INTO 数字
FROM sys.objects s1
CROSS JOIN sys.objects s2
CROSS JOIN sys.objects s3
CROSS JOIN sys.objects s4;
--?></sql_text>
<login_name>自分のログイン名が編集されました</login_name>
<wait_info>(99ms)LCK_M_X</wait_info>
<CPU> 9,750</CPU>
<tempdb_allocations> 713</tempdb_allocations>
<tempdb_current> 702</tempdb_current>
<blocking_session_id>NULL</blocking_session_id>
<blocked_session_count> 0</blocked_session_count>
<読み取り> 583,273</読み取り>
<書き込み> 537</書き込み>
<physical_reads> 50</physical_reads>
<使用済みメモリ> 3</使用済みメモリ>
<status>停止中</status>
<open_tran_count> 2</open_tran_count>
<percent_complete>NULL</percent_complete>
<host_name>自分のマシン名が編集されました</host_name>
<database_name>tempdb</database_name>
<program_name>Microsoft SQL Server Management Studio - クエリ</program_name>
<start_time>2013-11-23 23:48:19.473</start_time>
<login_time>2013-11-23 23:47:47.060</login_time>
<request_id>0</request_id>
<collection_time>2013-11-23 23:59:04.560</collection_time>
</RECORD>
</RESULTS1>
追加情報:
これを tempdb に入れる理由は、それが未使用のインストールで実行されることを意図したスクリプトの一部であり、tempdb がそこにあることが保証されているためです。前述したように、グローバル一時テーブルに変更しても違いはありません。