SELECT INTO 문의 진행


14

우리의 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_idas 인수 사용).

SQL Server에서 SELECT INTO 문은 하나의 DDL 및 DML 문이므로 암시 적 테이블 생성은 잠금 작업이 될 것입니다. 나는 여전히 성명서가 진행되는 동안 어떤 종류의 진보 정보를 얻는 영리한 방법이 있어야한다고 생각합니다.


전역 임시 테이블 ## TABLE을 사용한 경우 ## TABLE의 인덱스 열에서 개수를 사용하여 선택 (Select with count)을 수행하여 이미 기록 된 레코드 수를 얻고 기록 할 총 레코드 수를 대략적으로 계산할 수 있습니까?
CoveGeek

답변:


6

아직 커밋되지 않았기 때문에 rowsin sys.partitions이 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 행을 주석 처리하십시오.

한 세션에서 다음을 실행 한 다음 다른 세션에서 위의 쿼리를 반복적으로 실행하여 테스트했습니다.

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

1
이것은 창조적입니다. 큰 버퍼 풀을 열거하는 것이 매우 느리다는 경고를 추가하고 싶습니다.
usr

1
버퍼 풀에서 아직 페이지가 제거되지 않았다고 가정합니다.
Martin Smith

@MartinSmith 커밋 전에 페이지를 제거 할 수 있습니까?
Solomon Rutzky

5
@srutzky-그렇습니다. 트랜잭션 로그에는 롤백에 필요한 모든 정보가 있습니다. 더티 페이지는 디스크에 기록 될 수 있습니다. 예를 들어 체크 포인트 또는 Eager 기록기에 의해 특히이 경우 버퍼 풀에서 제거됩니다.
Martin Smith

7

모니터링 목적으로이 명령문이 실행되는 동안이 명령문의 진행 상황을 대략적으로 알고 싶습니다.

일회성입니까 아니면 진행 중입니까?

사전에 예상 할 수있는 필요가 있다면 * 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 ONSET STATISTICS XML ON. SSMS에서 "실제"실행 계획을 요청하는 것도 효과적입니다 (후자의 옵션을 설정하기 때문에).


나는 2 월에 이것을 다시 +1하는 것을 잊은 것처럼 보이지만, 나는 그것을 완전히 잊지 않았다 :). OP가 최소한 2014 년이기 때문에 방금이 관련 질문에 사용했습니다 : dba.stackexchange.com/questions/139191/… 지적 해 주셔서 감사합니다. 그것은 매우 편리한 DMV입니다 :-)
Solomon Rutzky

2
@ srutzky p 그것은 매우 유용합니다. 그리고 SSMS 2016 실시간 실행 계획을 이용했습니다 msdn.microsoft.com/en-gb/library/dn831878.aspx
Martin Smith

5

행 수를 얻는 방법이 없다고 생각하지만 다음을 보면 작성된 데이터 양을 추정 할 수 있습니다.

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(그리고 나는 그것을 권장하지 않습니다).


4

INSERT에서를 변경할 수 있다면

SELECT ... INTO DestTable FROM SrcTable

INSERT DestTable SELECT ... FROM SrcTable

그런 다음 select count(*) from DestTable with (nolock)쿼리가 작동합니다.

이것이 가능하지 않은 경우 sp_WhoIsActive를 사용하여 (또는 DMV를 조사) 쿼리 수행 횟수를 모니터링 할 수 있습니다. 이것은 다소 거친 게이지이지만 일반적으로 쓰는 수를 기준으로 줄을 지정하면 유용 할 수 있습니다.

추가 하면 위 의 내용으로 최소한의 로깅 을 얻을 INSERT수 있습니다 WITH (TABLOCK).


이 의견에 감사드립니다. 우리는 접근 방식 INTO 우리가 SELECT를 사용하는 이유 최소 로깅을 ... 가져올 (게으른 ...의 또한 우리 때문에있는 거 종류)

1
INSERT추가 하면 위 의 내용으로 최소한의 로깅을 얻을 수 있어야합니다WITH(TABLOCK)
James Anderson

@JamesAnderson-테이블이 힙으로 남겨지면 BULK_OPERATION잠금 이 걸리기 때문에 다시 차단됩니다 .
Martin Smith
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.