SELECT INTO ifadesinin ilerlemesi


14

ETL akışımızın uzun süredir devam eden bir SELECT INTO ifadesi var, bu da anında bir tablo oluşturuyor ve birkaç yüz milyon kayıtla dolduruyor.

İfade benzer bir şeye benziyor SELECT ... INTO DestTable FROM SrcTable

İzleme amacıyla, bu ifadenin yürütülürken ilerleyişi hakkında kabaca bir fikir edinmek istiyoruz (yaklaşık satır sayısı, yazılı bayt sayısı veya benzeri).

Aşağıdakileri boşuna denedik:

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

Ayrıca, işlemi görebiliriz sys.dm_tran_active_transactions, ancak belirli bir durumda etkilenen satırların sayısını elde etmenin bir yolunu bulamadım transaction_id( @@ROWCOUNTbelki de benzer bir şey , ancak transaction_idargüman olarak).

SQL Server'da SELECT INTO deyiminin hem DDL hem de DML deyimi olduğunu ve örtük tablo oluşturma işleminin bir kilitleme işlemi olacağını anlıyorum. Ben hala ifade çalışırken bir tür ilerleme bilgi elde etmek için akıllı bir yol olması gerektiğini düşünüyorum.


Genel bir geçici tablo ## TABLE kullandıysanız, ## TABLE'daki dizin sütununda önceden yazılan kayıtların sayısını almak ve yazılacak toplam kayıt miktarına yaklaşık olarak bir Sayım seçebilir misiniz?
CoveGeek

Yanıtlar:


6

Henüz işlenmediği için rowsiçinde sys.partitions0 olduğundan şüpheleniyorum . Ancak bu, İşlem gerçekleştirildiğinde SQL Server'ın oraya ne gideceğinin farkında olmadığı anlamına gelmez. Anahtar, işlemin COMMIT veya ROLLBACK'ine bakılmaksızın, önce tüm işlemlerin Arabellek Havuzu'ndan (yani bellek) geçtiğini hatırlamaktır. Bu nedenle, sys.dm_os_buffer_descriptorsbu bilgileri arayabiliriz :

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

Ayrıntıları görmek istiyorsanız, SELECTlistedeki öğelerin ilk satırını kaldırın , kalan 3 satırı yorumlayın.

Bir oturumda aşağıdaki çalıştırarak ve daha sonra tekrar tekrar başka bir yukarıdaki sorgu çalıştırarak test.

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

1
Bu yaratıcı. Sadece büyük bir tampon havuzunu numaralandırmanın çok yavaş olduğuna dair bir uyarı eklemek istiyorum.
usr

1
Bu, arabellek havuzundan henüz sayfa çıkarılmadığını varsayar.
Martin Smith

@MartinSmith Sayfalar taahhütten önce çıkarılabilir mi?
Solomon Rutzky

5
@srutzky - evet. İşlem günlüğü geri almak için gereken tüm bilgilere sahiptir. Kirli sayfalar diske yazılabilir - örneğin bir kontrol noktasında veya Eager yazarı tarafından özellikle bu durumda arabellek havuzundan kaldırılabilir.
Martin Smith

7

İzleme amacıyla, bu ifadenin yürütülmesi sırasında kaydedilen ilerlemeler hakkında kabaca bir fikir edinmek istiyoruz.

Biri kapalı mı yoksa devam mı?

Bu önceden tahmin edilebilecek bir ihtiyaçsa * kullanabilirsiniz sys.dm_exec_query_profiles

Bağlantı 1 (oturum 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;

Bağlantı 2

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

Paralellik kullanıyorsaSELECT INTO , döndürülen satır sayılarını toplamanız gerekebilir .

* Bu DMV'yi kullanarak izlemek istediğiniz oturumun, SET STATISTICS PROFILE ONveya kullanılarak istatistik toplama için etkinleştirilmesi gerekir SET STATISTICS XML ON. SSMS'den "gerçek" bir yürütme planı istemek de işe yarar (ikinci seçeneği ayarladığından).


Bu Şubat ayında +1 geri unuttum görünüyor, ama tamamen unutmadım :). OP ile ilgili en az 2014 olduğu için bu konuyla ilgili sorudan yeni yararlandım : dba.stackexchange.com/questions/139191/… Bunu işaret ettiğiniz için teşekkürler; oldukça kullanışlı bir DMV :-)
Solomon Rutzky 23:16 '

2
@srutzky evet çok faydalı. Ve SSMS 2016 canlı yürütme planlarında kullanıldı msdn.microsoft.com/en-gb/library/dn831878.aspx
Martin Smith

5

Satır sayısını almanın bir yolu olduğunu düşünmüyorum, ancak aşağıdakilere bakarak yazılan veri miktarını tahmin edebilirsiniz:

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

Yığının tamamlandığında kaç sayfa alması gerektiği konusunda bir tür fikriniz varsa,% tamamlandı çalışabilmeniz gerekir. Tablo büyüdükçe, ikinci sorgu hızlı olmaz. Ve muhtemelen yukarıda çalıştırmak için en güvenli READ UNCOMMITTED(ve çoğu zaman bunu tavsiye etmiyorum, herhangi bir şey için).


4

Eğer INSERTbir

SELECT ... INTO DestTable FROM SrcTable

bir

INSERT DestTable SELECT ... FROM SrcTable

sonra select count(*) from DestTable with (nolock)sorgu çalışacak.

Bu mümkün değilse, sorgunun kaç yazma işlemini izlemek için sp_WhoIsActive (veya DMV'leri inceleyebilirsiniz) kullanabilirsiniz. Bu oldukça kaba bir ölçüt olacaktır, ancak normalde yaptığı yazma sayısını temel alırsanız yararlı olabilir.

Eklerseniz , INSERTyukarıdakilerle minimum günlük kaydı alabilmeniz gerekir WITH (TABLOCK).


Bu yorumunuz için teşekkürler. Minimum kayıt almak istiyoruz, bu yüzden SELECT ... INTO yaklaşımını kullanıyoruz (ve ayrıca biraz tembel olduğumuz için)
Dan

1
Eğer INSERTeklerseniz yukarıdakilerle minimum kayıt alabilmelisinizWITH(TABLOCK)
James Anderson

@JamesAnderson - Tablo bir yığın olarak bırakılırsa, bu sadece bir BULK_OPERATIONkilit alır gibi tekrar engellemeye neden olur .
Martin Smith
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.