Tiến trình của câu lệnh CHỌN VÀO


14

Luồng ETL của chúng tôi có một câu lệnh CHỌN VÀO chạy dài, đó là tạo một bảng một cách nhanh chóng và tạo ra nó với hàng trăm triệu bản ghi.

Tuyên bố trông giống như SELECT ... INTO DestTable FROM SrcTable

Đối với mục đích giám sát, chúng tôi muốn có được một ý tưởng sơ bộ về tiến trình của tuyên bố này, trong khi nó đang thực thi (khoảng hàng, số byte được viết hoặc tương tự).

Chúng tôi đã thử những điều sau đây nhưng không có kết quả:

-- 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')

Hơn nữa, chúng ta có thể thấy giao dịch trong sys.dm_tran_active_transactions, nhưng tôi không thể tìm ra cách để có được số lượng hàng bị ảnh hưởng trên một số nhất định transaction_id(một cái gì đó tương tự như @@ROWCOUNTcó lẽ, nhưng với transaction_idđối số là).

Tôi hiểu rằng trên SQL Server, câu lệnh CHỌN VÀO là cả câu lệnh DDL và DML trong một, và do đó, việc tạo bảng ẩn sẽ là một hoạt động khóa. Tôi vẫn nghĩ rằng phải có một số cách thông minh để có được một số loại thông tin tiến bộ trong khi tuyên bố đang chạy.


Nếu bạn đã sử dụng bảng tạm thời toàn cầu ## TABLE, bạn có thể thực hiện Chọn với số đếm trên cột chỉ mục trên ## TABLE để lấy số lượng bản ghi đã ghi và xấp xỉ tổng số bản ghi được ghi không?
CoveGeek

Câu trả lời:


6

Tôi nghi ngờ rằng rowstrong sys.partitions0 là do chưa được cam kết. Nhưng điều này không có nghĩa là SQL Server không biết điều gì sẽ xảy ra nếu Giao dịch được cam kết. Điều quan trọng là ghi nhớ rằng tất cả các hoạt động đều đi qua Vùng đệm (tức là bộ nhớ) trước, bất kể CAM KẾT hay ROLLBACK của hoạt động. Do đó, chúng ta có thể tìm kiếm sys.dm_os_buffer_descriptorsthông tin đó:

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')

Nếu bạn muốn xem chi tiết, bỏ ghi chú hàng đầu tiên trong SELECTdanh sách, hãy nhận xét 3 dòng còn lại.

Tôi đã kiểm tra bằng cách chạy các mục sau trong một Phiên và sau đó liên tục chạy truy vấn ở trên trong một Phiên khác.

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

1
Đây là sáng tạo. Chỉ muốn thêm một cảnh báo rằng việc liệt kê một vùng đệm lớn là rất chậm.
usr

1
Điều này không cho rằng chưa có trang nào bị đuổi khỏi vùng đệm.
Martin Smith

@MartinSmith Các trang có thể bị đuổi trước khi cam kết không?
Solomon Rutzky

5
@srutzky - vâng. Nhật ký giao dịch có tất cả các thông tin cần thiết để khôi phục. Các trang bẩn có thể được ghi vào đĩa - ví dụ: tại một điểm kiểm tra hoặc bởi người viết Eager đặc biệt trong trường hợp này sau đó được xóa khỏi nhóm bộ đệm.
Martin Smith

7

Đối với mục đích giám sát, chúng tôi muốn có được một ý tưởng sơ bộ về tiến trình của tuyên bố này, trong khi nó đang được thực thi.

Một tắt hoặc liên tục?

Nếu đây là nhu cầu có thể dự đoán trước * bạn có thể sử dụng sys.dm_exec_query_profiles

Kết nối 1 (phiên 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;

Kết nối 2

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

Bạn có thể cần tính tổng các hàng được trả về nếu SELECT INTOđang sử dụng song song .

* Phiên bạn muốn theo dõi bằng DMV này phải được bật để thu thập số liệu thống kê bằng cách sử dụng SET STATISTICS PROFILE ONhoặc SET STATISTICS XML ON. Yêu cầu một kế hoạch thực hiện "thực tế" từ SSMS cũng hoạt động (vì nó đặt tùy chọn sau).


Có vẻ như tôi đã quên +1 điều này trở lại vào tháng 2, nhưng tôi đã không quên nó hoàn toàn :). Tôi mới sử dụng nó cho Câu hỏi liên quan này vì OP ít nhất là vào năm 2014: dba.stackexchange.com/questions/139191/ nam Cảm ơn vì đã chỉ ra điều này; nó khá là DMV tiện dụng :-)
Solomon Rutzky

2
@srutzky vâng nó rất hữu ích. Và đã sử dụng trong các kế hoạch thực hiện trực tiếp SSMS 2016 msdn.microsoft.com/en-gb/l Library / dn831878.aspx
Martin Smith

5

Tôi không nghĩ có cách nào để đếm số hàng, nhưng bạn có thể ước tính lượng dữ liệu được viết bằng cách xem:

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');

Nếu bạn có một số loại ý tưởng về việc heap sẽ chiếm bao nhiêu trang khi hoàn thành, bạn sẽ có thể hoàn thành% hoàn thành. Truy vấn sau sẽ không nhanh khi bảng trở nên lớn hơn. Và có lẽ an toàn nhất để chạy ở trên READ UNCOMMITTED(và không thường xuyên tôi khuyên bạn nên làm điều đó).


4

Nếu bạn có thể thay đổi INSERTtừ một

SELECT ... INTO DestTable FROM SrcTable

đến một

INSERT DestTable SELECT ... FROM SrcTable

sau đó của bạn select count(*) from DestTable with (nolock) truy vấn sẽ làm việc.

Nếu điều này là không thể thì bạn có thể sử dụng sp_WhoIsActive (hoặc đi sâu vào DMV) để theo dõi số lượng ghi truy vấn. Đây sẽ là một thước đo khá thô nhưng có thể hữu ích nếu bạn căn cứ vào số lượng ghi mà nó thường làm.

Bạn sẽ có thể nhận được đăng nhập tối thiểu với INSERTở trên nếu bạn thêm WITH (TABLOCK).


Cảm ơn đã bình luận điều này. Chúng tôi muốn có được ghi nhật ký tối thiểu, đó là lý do tại sao chúng tôi sử dụng phương pháp CHỌN ... VÀO (và cũng vì chúng tôi lười biếng ...)
Dan

1
Bạn sẽ có thể nhận được nhật ký tối thiểu với những điều INSERTtrên nếu bạn thêmWITH(TABLOCK)
James Anderson

@JamesAnderson - Nếu bảng còn lại là một đống, điều này sẽ chỉ gây ra chặn lại khi nó bị BULK_OPERATIONkhóa.
Martin Smith
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.