18

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 がそこにあることが保証されているためです。前述したように、グローバル一時テーブルに変更しても違いはありません。

4

2 に答える 2

9

この問題を追うのではなく、modelデータベースに一度テーブルを作成すると、tempdb自動的にテーブルが作成されます。

実際の問題については、わかりません。私の最初の推測は、tempdb ファイルの初期サイズが非常に小さい (1 MB など) ことです。したがって、テーブルを作成するときは、それに対応するためにファイルを拡張する必要があります。これは、特にファイルの即時初期化を有効にしていない場合は非常にコストがかかる可能性があり、必要なアクティビティに対応するためにログを大きくするのにも非常にコストがかかる可能性があります。

それ以外は、推測を続けることができますが、実際に何が起こっているのかを調査する方が適しています. 尋ねたい質問:

  1. テーブルを作成しようとしている spid の場合、何sys.dm_exec_requestsと言っていwait_typeますか?
  2. それはありblocking_session_idますか?
  3. もしそうなら、そのセッションは何をしていますか?
于 2013-11-22T22:19:15.033 に答える