Bir veri ambarı senaryosunda “otomatik güncelleme istatistikleri” ni devre dışı bırakmalı mıyım?


12

SQL Server'da 200 GB veri ambarım var.

Bazı sorgular için gerçekten yavaş yürütme süreleri yaşıyorum; örneğin . deleteile basit bir sorgu için 12 saat inner join.

Yürütme planları ile biraz araştırma yaptıktan sonra, WITH FULLSCANseçeneği kullanarak sorguda yer alan 2 tablonun istatistiklerini güncelledim .

Sorgu şimdi bir saniyeden daha kısa sürede yürütüldüğünden, istatistiklerin güncel olmadığı anlaşılıyor.

Veri ambarı yüklendikten sonra auto update statisticsveritabanında devre dışı bırakmayı ve UPDATE STATISTICSmanuel olarak çalıştırmayı düşünüyorum . Veri ambarı, geceleri günlük olarak kaynak ERP sisteminden aşamalı olarak yüklenir.

auto update statisticsVeri ambarı senaryolarında gerçekten yararlı olmadığını varsayarak doğru muyum ? Bunun yerine, veriler yüklendikten sonra istatistikleri manuel olarak güncellemek daha mantıklı mı?


Bu istatistiklerle ilgili çok iyi bir okuma: simple-talk.com/sql/performance/… 1TB db'deki istatistikleri güncellemek için Ola'nın çözüm ola.hallengren.com/… kullanarak günlük bir iş de yapıyoruz . Otomatik güncelleme istatistikleri seçeneğini devre dışı bırakmam.
Joy Walker

1
Bu, tablolarınızda kaç kayıt olduğuna ve toplu olarak ne kadar kayıt eklediğinize bağlıdır. Bir gece 20 milyon satır eklediğiniz 1b satırlık bir tabloda, istatistikleriniz her 10 günde bir güncellenir, bu da harika değildir.
JNK

2
Sadece FYI - istatistik güncelleme eşiğini sabit% 20'den dinamik bir yüzde oranına değiştirmek için bir izleme bayrağı (2371) var. Daha fazlasını burada görebilirsiniz: blogs.msdn.com/b/saponsqlserver/archive/2011/09/07/…
DaniSQL

Çok bilgilendirici bağlantılar, teşekkürler! @JNK: Evet, büyük bir veri tabanı. Evreleme tablosunda 300m + satır vardır ve güne bağlı olarak günde 1m ila 10m arasında bir şey ekliyoruz. Aşağıdaki cevapta önerildiği gibi istatistiklere daha yakından bakacağız.
saso

Yanıtlar:


11

İstatistiklerin otomatik_güncellemesi gerçekleştiğinde bir teknik inceleme . İstatistiklere ilişkin otomatik güncellemeler karşısında dikkat çeken noktalar şunlardır:

  • Tablo boyutu 0'dan> 0 satıra gitti (test 1).
  • İstatistikler toplandığında tablodaki satır sayısı 500 veya daha azdı ve istatistik nesnesinin önde gelen sütununun colmodctr değeri o zamandan bu yana 500'den fazla değişti (test 2).
  • İstatistikler toplandığında tablonun 500'den fazla satırı vardı ve istatistik nesnesinin önde gelen sütununun colmodctr değeri, istatistikler toplandığında tablodaki satır sayısının% 500 + 20'sinden fazla değişti (test 3) .

@JNK, bir yorumda, bir tabloda 1 milyar satırınız varsa, bir güncellemeyi tetiklemek için istatistikteki ilk sütuna 20.000.5000 yazmanız gerektiğini vurguladı.

Aşağıdaki yapıyı ele alalım:

CREATE TABLE dbo.test_table (
    test_table_id INTEGER IDENTITY(1,1) NOT NULL, 
    test_table_value VARCHAR(50), 
    test_table_value2 BIGINT, 
    test_table_value3 NUMERIC(10,2)
);

CREATE CLUSTERED INDEX cix_test_table ON dbo.test_table (test_table_id, test_table_value);

Şimdi istatistik ülkesinde neler olduğunu kontrol edebiliriz.

select * 
    from sys.stats
        where object_id = OBJECT_ID('dbo.test_table')

stat_container

Bununla birlikte, bunun anlamlı bir istatistik nesnesi olup olmadığını görmek için şunları yapmamız gerekir:

dbcc show_statistics('dbo.test_table',cix_test_table)

histogram

Yani bu istatistik güncellenmedi. Çünkü istatistik bir SELECToluşum gerçekleşene kadar güncellenmemiş gibi görünüyor ve o zaman bile SELECTSQL Server'ın histogramının dışında kalması gerekiyor. İşte bunu test etmek için koştum bir test komut dosyası:

    CREATE TABLE test_table (
        test_table_id INTEGER IDENTITY(1,1) NOT NULL, 
        test_table_value VARCHAR(50), 
        test_table_value2 BIGINT, 
        test_table_value3 NUMERIC(10,2)
    );

    CREATE CLUSTERED INDEX cix_test_table ON test_table (test_table_id, test_table_value);

    ALTER TABLE test_table ADD CONSTRAINT pk_test_table PRIMARY KEY  (test_table_id)

    SELECT * 
        FROM sys.stats
            WHERE object_id = OBJECT_ID('dbo.test_table')

    --DBCC SHOW_STATISTICS('dbo.test_table',pk_test_table)
    DBCC SHOW_STATISTICS('dbo.test_table',cix_test_table) WITH STAT_HEADER;

declare @test int = 0

WHILE @test < 1
    BEGIN
        INSERT INTO test_table (test_table_value,test_table_value2,test_table_value3) VALUES
            ('stats test' + CAST(@test AS VARCHAR(10)),@test, @test)
        SET @test = @test + 1;
    END

SELECT 'one row|select < 1', * FROM test_table WHERE test_table_id < 1;
--DBCC SHOW_STATISTICS('dbo.test_table',pk_test_table);
DBCC SHOW_STATISTICS('dbo.test_table',cix_test_table) WITH STAT_HEADER;

SET @test = 1

WHILE @test < 500
    BEGIN
        INSERT INTO test_table (test_table_value,test_table_value2,test_table_value3) VALUES
            ('stats test' + CAST(@test AS VARCHAR(10)),@test, @test)
        SET @test = @test + 1;
    END

SELECT '100 rows(add 99)|select < 100',* FROM test_table WHERE test_table_id < 100;
--DBCC SHOW_STATISTICS('dbo.test_table',pk_test_table);
DBCC SHOW_STATISTICS('dbo.test_table',cix_test_table) WITH STAT_HEADER;
--get the table up to 500 rows/changes
WHILE @test < 500
    BEGIN
        INSERT INTO test_table (test_table_value,test_table_value2,test_table_value3) VALUES
            ('stats test' + CAST(@test AS VARCHAR(10)),@test, @test)
        SET @test = @test + 1;
    END
SELECT '500 rows(add 400)|select < 100',* FROM test_table WHERE test_table_id < 100;
DBCC SHOW_STATISTICS('dbo.test_table',cix_test_table) WITH STAT_HEADER;
SELECT '500 rows(add 400)|select < 500',* FROM test_table WHERE test_table_id < 500;
--DBCC SHOW_STATISTICS('dbo.test_table',pk_test_table);
DBCC SHOW_STATISTICS('dbo.test_table',cix_test_table) WITH STAT_HEADER;
--bump it to 501
SET @test = 500;
WHILE @test < 501
    BEGIN
        INSERT INTO test_table (test_table_value,test_table_value2,test_table_value3) VALUES
            ('stats test' + CAST(@test AS VARCHAR(10)),@test, @test)
        SET @test = @test + 1;
    END


SELECT '501 rows(add 1)|select < 501',* FROM test_table WHERE test_table_id < 501;
--DBCC SHOW_STATISTICS('dbo.test_table',pk_test_table);
DBCC SHOW_STATISTICS('dbo.test_table',cix_test_table) WITH STAT_HEADER;

--bump it to 600
SET @test = 501;
WHILE @test < 600
    BEGIN
        INSERT INTO test_table (test_table_value,test_table_value2,test_table_value3) VALUES
            ('stats test' + CAST(@test AS VARCHAR(10)),@test, @test)
        SET @test = @test + 1;
    END

SELECT '600 rows (add 100)|select < 600',* FROM test_table WHERE test_table_id < 600;
--DBCC SHOW_STATISTICS('dbo.test_table',pk_test_table);
DBCC SHOW_STATISTICS('dbo.test_table',cix_test_table) WITH STAT_HEADER;

--bump it to 700
SET @test = 600;
WHILE @test < 700
    BEGIN
        INSERT INTO test_table (test_table_value,test_table_value2,test_table_value3) VALUES
            ('stats test' + CAST(@test AS VARCHAR(10)),@test, @test)
        SET @test = @test + 1;
    END

SELECT '700 rows (add 100)|select < 700', * FROM test_table WHERE test_table_id < 700;
--DBCC SHOW_STATISTICS('dbo.test_table',pk_test_table);
DBCC SHOW_STATISTICS('dbo.test_table',cix_test_table) WITH STAT_HEADER;

--bump it to 1200
SET @test = 700;
WHILE @test < 1200
    BEGIN
        INSERT INTO test_table (test_table_value,test_table_value2,test_table_value3) VALUES
            ('stats test' + CAST(@test AS VARCHAR(10)),@test, @test)
        SET @test = @test + 1;
    END

SELECT '1200 rows (add 500)|select < 1200',* FROM test_table WHERE test_table_id < 1200;
--DBCC SHOW_STATISTICS('dbo.test_table',pk_test_table);
DBCC SHOW_STATISTICS('dbo.test_table',cix_test_table) WITH STAT_HEADER;
--DROP TABLE test_table

Auto_update istatistiklerini körü körüne devre dışı bırakmak yerine, veri kümenizi eğriltme açısından incelemeye çalışırım. Verileriniz önemli ölçüde eğriltme gösteriyorsa, filtrelenmiş istatistikler oluşturmayı ve ardından istatistik güncellemelerini manuel olarak yönetmenin doğru eylem yöntemi olup olmadığına karar vermeniz gerekir .

Eğriliği analiz etmek için incelemek istediğiniz belirli stat / dizin kombinasyonunda DBCC SHOW_STATISTICS(<stat_object>, <index_name>);(yukarıdaki komut dosyasında) olmadan çalıştırmanız gerekir WITH STAT_HEADER. Çarpıklığınızı görmenin hızlı bir yolu, histograma (üçüncü sonuç kümesi) bakmak ve varyansınızı kontrol etmek olacaktır EQ_ROWS. Oldukça tutarlıysa, çarpıklığınız minimumdur. Adımlamak için RANGE_ROWSsütuna bakarsınız ve buradaki varyansa bakarsınız, çünkü bu her adım arasında kaç satır olduğunu ölçer. Son olarak, [All density]sonucu DENSITY_VECTOR(ikinci sonuç kümesinden) alabilir ve (ilk sonuç kümesindeki) [Rows Sampled]değerle çarpabilir STAT_HEADERve bu sütundaki bir sorgu için ortalama beklentinin ne olacağını görebilirsiniz. Bu ortalamayıEQ_ROWS ve önemli ölçüde değiştiği birçok yer varsa, çarpıklık yaşarsınız.

Eğriliğiniz RANGE_ROWSolduğunu fark ederseniz, bu değerler hakkında daha iyi tahminler için ek adımlar atabilmeniz için çok yüksek aralıklarda filtrelenmiş istatistikler oluşturmayı düşünmeniz gerekir .

Bu filtrelenmiş istatistikleri yerleştirdikten sonra, istatistikleri manuel olarak güncelleme olasılığına bakabilirsiniz.


Kapsamlı cevap için teşekkür ederim. İstatistiklerle ilgili çok fazla deneyimim yok ve düşündüğüm kadar zor görünüyor. Kesinlikle daha yakından bakacak ve yönergelerinizi takip edecektir.
saso
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.