İkinci INSERT
ifade neden birinciden ~ 5 kat daha yavaş?
Üretilen günlük verisi miktarından, ikincisinin minimum günlük kaydı için uygun olmadığını düşünüyorum. Ancak, Veri Yükleme Performansı Kılavuzu'ndaki belgeler her iki ek parçanın da minimum düzeyde günlüğe kaydedilebileceğini gösterir. Peki, minimum günlük kaydı temel performans farkı ise, neden ikinci sorgu minimum günlük kaydı için uygun olmaz? Durumu iyileştirmek için ne yapılabilir?
Sorgu 1: INSERT ... WITH (TABLOCK) kullanarak 5MM satırlar ekleme
Yığına 5MM satır ekleyen aşağıdaki sorguyu düşünün. Bu sorgu , tarafından bildirildiği şekilde işlem günlüğü verilerini yürütür 1 second
ve üretir .64MB
sys.dm_tran_database_transactions
CREATE TABLE dbo.minimalLoggingTest (n INT NOT NULL)
GO
INSERT INTO dbo.minimalLoggingTest WITH (TABLOCK) (n)
SELECT n
-- Any table/view/sub-query that correctly estimates that it will generate 5MM rows
FROM dbo.fiveMillionNumbers
-- Provides greater consistency on my laptop, where other processes are running
OPTION (MAXDOP 1)
GO
Sorgu # 2: Aynı verileri ekleme, ancak SQL satırların sayısını hafife alıyor
Şimdi, tamamen aynı veriler üzerinde çalışan ancak SELECT
kardinalite tahmininin çok düşük olduğu bir tablodan (veya gerçek üretim durumumda birçok birleşimle karmaşık bir ifadeden) oluşan bu çok benzer sorguyu düşünün . Bu sorgu yürütülür 5.5 seconds
ve 461MB
işlem günlüğü verisi oluşturur.
CREATE TABLE dbo.minimalLoggingTest (n INT NOT NULL)
GO
INSERT INTO dbo.minimalLoggingTest WITH (TABLOCK) (n)
SELECT n
-- Any table/view/sub-query that produces 5MM rows but SQL estimates just 1000 rows
FROM dbo.fiveMillionNumbersBadEstimate
-- Provides greater consistency on my laptop, where other processes are running
OPTION (MAXDOP 1)
GO
Komut dosyasının tamamı
Test verilerini oluşturmak ve bu senaryolardan birini yürütmek için tam komut dosyası kümesi için bu Pastebin'e bakın . SIMPLE
Kurtarma modelinde bir veritabanı kullanmanız gerektiğini unutmayın .
İş bağlamı
Milyonlarca veri satırında yarı sık sık hareket ediyoruz ve bu işlemlerin hem yürütme süresi hem de disk G / Ç yükü açısından mümkün olduğunca verimli olması önemlidir. Başlangıçta bir yığın tablosu oluşturmanın ve kullanmanın INSERT...WITH (TABLOCK)
bunu yapmanın iyi bir yolu olduğu izlenimi altındaydık , ancak gerçek bir üretim senaryosunda yukarıda gösterilen durumu gözlemlediğimizden (daha karmaşık sorgular olsa da, basitleştirilmiş sürüm).
SELECT
için sonuç kümesini oluşturan çok sayıda birleşim içeren karmaşık bir ifade vardırINSERT
. Bu birleşimler, son tablo ekleme operatörü için kötü kardinalite tahminleri üretir (ki bu, hatalıUPDATE STATISTICS
çağrı yoluyla repro komut dosyasında simüle ettim ) ve bu nedenleUPDATE STATISTICS
sorunu düzeltmek için bir komut vermek kadar basit değildir . Sorguyu basitleştirmenin, Kardinalite Tahmincisi'nin daha kolay anlaşılabilmesi için iyi bir yaklaşım olabileceğini tamamen kabul ediyorum, ancak verilen karmaşık iş mantığını uygulamak bir üç değer değildir.