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.objects
100 万の結果行に等しくなるようにその数を 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 がそこにあることが保証されているためです。前述したように、グローバル一時テーブルに変更しても違いはありません。