web-dev-qa-db-ja.com

SELECT INTOステートメントの進行状況

私たちのETLフローには長時間実行されるSELECT INTOステートメントがあり、それはその場でテーブルを作成し、それに数億のレコードを投入します。

ステートメントはSELECT ... INTO DestTable FROM SrcTableのようになります。

監視の目的で、実行中のこのステートメントの進行状況の概算を取得します(およその行数、書き込まれたバイト数など)。

次のことを試みたが、役に立たなかった。

-- Is blocked by the SELECT INTO statement:
select count(*) from DestTable with (nolock)

-- Returns 0, 0:
select rows, rowmodctr
from sysindexes with (nolock)
where id = object_id('DestTable')

-- Returns 0:
select rows
from sys.partitions
where object_id = object_id('DestTable')

さらに、sys.dm_tran_active_transactionsでトランザクションを確認できますが、特定のtransaction_idで影響を受けた行の数を取得する方法を見つけることができませんでした(おそらく@@ROWCOUNTに似ていますが、 transaction_idを引数として)。

SQL Serverでは、SELECT INTOステートメントがDDLステートメントとDMLステートメントの両方であるということを理解しています。そのため、暗黙的なテーブル作成はロック操作になります。ステートメントの実行中に何らかの進行情報を取得するための巧妙な方法がまだあると私はまだ思います。

14
Dan

まだコミットされていないため、sys.partitionsrowsは0だと思います。ただし、これは、トランザクションがコミットした場合にSQL Serverが何を実行するかを認識していないことを意味するものではありません。重要なのは、操作のCOMMITまたはROLLBACKに関係なく、すべての操作が最初にバッファプール(つまりメモリ)を通過することを覚えておくことです。したがって、その情報についてsys.dm_os_buffer_descriptorsを調べることができます。

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;

SELECT  --OBJECT_NAME(sp.[object_id]) AS [TableName], sdobd.*, '---', sp.*, '---', sau.*
       SUM(sdobd.[row_count]) AS [BufferPoolRows],
       SUM(sp.[rows]) AS [AllocatedRows],
       COUNT(*) AS [DataPages]
FROM sys.dm_os_buffer_descriptors sdobd
INNER JOIN  sys.allocation_units sau
        ON sau.[allocation_unit_id] = sdobd.[allocation_unit_id]
INNER JOIN  sys.partitions sp
        ON  (   sau.[type] = 1
            AND sau.[container_id] = sp.[partition_id]) -- IN_ROW_DATA
        OR  (   sau.[type] = 2
            AND sau.[container_id] = sp.[hobt_id]) -- LOB_DATA
        OR  (   sau.[type] = 3
            AND sau.[container_id] = sp.[partition_id]) -- ROW_OVERFLOW_DATA
WHERE   sdobd.[database_id] = DB_ID()
AND     sdobd.[page_type] = N'DATA_PAGE'
AND     sp.[object_id] = (SELECT so.[object_id]
                          FROM   sys.objects so
                          WHERE  so.[name] = 'TestDump')

詳細を表示するには、SELECTリストの最初の行のコメントを外し、残りの3行をコメント化します。

1つのセッションで以下を実行し、別のセッションで上記のクエリを繰り返し実行してテストしました。

SELECT so1.*
INTO   dbo.TestDump
FROM   sys.objects so1
CROSS JOIN sys.objects so2
CROSS JOIN sys.objects so3;
6
Solomon Rutzky

監視の目的で、このステートメントの実行中に、ステートメントの進行状況の大まかな概要を知りたいと思います。

単発か継続中か?

これが事前に予想できるニーズである場合* sys.dm_exec_query_profiles を使用できます

接続1(セッション55)

SET STATISTICS XML ON

SELECT so1.*
INTO   dbo.TestDump
FROM   sys.all_objects so1
CROSS JOIN sys.all_objects so2
CROSS JOIN sys.all_objects so3
CROSS JOIN sys.all_objects so4
CROSS JOIN sys.all_objects so5;

接続2

select row_count
from sys.dm_exec_query_profiles
WHERE physical_operator_name = 'Table Insert' 
    AND session_id = 55;

SELECT INTO並列処理を使用 の場合、返される行数を合計する必要がある場合があります。

*このDMVを使用して監視するセッションでは、SET STATISTICS PROFILE ONまたはSET STATISTICS XML ONを使用した統計収集を有効にする必要があります。 SSMSから「実際の」実行計画を要求することもできます(後者のオプションが設定されているため)。

7
Martin Smith

行数を取得する方法はないと思いますが、以下を参照することで書き込まれたデータの量を見積もることができます。

SELECT writes 
  FROM sys.dm_exec_requests WHERE session_id = <x>;

SELECT COUNT(*) FROM sys.dm_db_database_page_allocations
(<dbid>, OBJECT_ID(N'dbo.newtablename'), 0, NULL, 'LIMITED');

完了時にヒープがいくつのページを占有する必要があるかについて何らかの考えがある場合は、完了率を計算できるはずです。後者のクエリは、テーブルが大きくなると高速になりません。そして、おそらく上記をREAD UNCOMMITTEDの下で実行するのが最も安全です(そして、私は何のためにもそれをお勧めすることはあまりありません)。

5
Aaron Bertrand

INSERT

_SELECT ... INTO DestTable FROM SrcTable
_

_INSERT DestTable SELECT ... FROM SrcTable
_

次に、select count(*) from DestTable with (nolock)クエリが機能します。

これが不可能な場合は、sp_WhoIsActive(またはDMVの詳細)を使用して、クエリが行う書き込み数を監視できます。これはかなり大まかなゲージになりますが、通常行う書き込み数をベースライン化する場合に役立ちます。

WITH (TABLOCK)を追加すると、上記のINSERT最小限のロギング を取得できるはずです。

4
James Anderson