Zaten oldukça uzun olacağı ve SQL Server'ın verileri histogram adımlarına nasıl eklediğiyle ilgileniyorsanız, bu yayını tek sütun istatistiklerini tartışmakla sınırlayacağım. Çok sütunlu istatistikler için, histogram yalnızca ön sütunda oluşturulur.
SQL Server bir istatistik güncelleştirmesinin gerekli olduğunu belirlediğinde, bir tablonun tüm verilerini veya tablonun verilerinin bir örneğini okuyan gizli bir sorguyu başlatır. Bu sorguları genişletilmiş etkinliklerle görüntüleyebilirsiniz. StatMan
SQL Server'da, histogramların oluşturulmasında rol oynayan bir işlev vardır . Basit istatistik nesneleri için en az iki farklı StatMan
sorgu türü vardır (hızlı istatistik güncellemeleri için farklı sorgular vardır ve bölümlenmiş tablolardaki artımlı istatistikler özelliğinin de farklı bir sorgu kullandığından şüpheleniyorum).
Birincisi, filtreleme olmadan tablodaki tüm verileri alır. Tablo çok küçük olduğunda veya FULLSCAN
seçenekle istatistik topladığınızda bunu görebilirsiniz :
CREATE TABLE X_SHOW_ME_STATMAN (N INT);
CREATE STATISTICS X_STAT_X_SHOW_ME_STATMAN ON X_SHOW_ME_STATMAN (N);
-- after gathering stats with 1 row in table
SELECT StatMan([SC0]) FROM
(
SELECT TOP 100 PERCENT [N] AS [SC0]
FROM [dbo].[X_SHOW_ME_STATMAN] WITH (READUNCOMMITTED)
ORDER BY [SC0]
) AS _MS_UPDSTATS_TBL
OPTION (MAXDOP 16);
SQL Server tablonun büyüklüğüne göre otomatik örneklem boyutunu seçer (bence tablodaki satır ve sayfa sayısıdır). Bir tablo çok büyükse, otomatik numune boyutu% 100'ün altına düşer. İşte 1M satırları ile aynı tablo için ne var:
-- after gathering stats with 1 M rows in table
SELECT StatMan([SC0], [SB0000]) FROM
(
SELECT TOP 100 PERCENT [SC0], step_direction([SC0]) over (order by NULL) AS [SB0000]
FROM
(
SELECT [N] AS [SC0]
FROM [dbo].[X_SHOW_ME_STATMAN] TABLESAMPLE SYSTEM (6.666667e+001 PERCENT) WITH (READUNCOMMITTED)
) AS _MS_UPDSTATS_TBL_HELPER
ORDER BY [SC0], [SB0000]
) AS _MS_UPDSTATS_TBL
OPTION (MAXDOP 1);
TABLESAMPLE
olduğu belgelenmiş ancak StatMan ve step_direction değildir. burada SQL Server histogram oluşturmak için tablodaki verilerin yaklaşık% 66.6'sını örnekler. Bunun anlamı, FULLSCAN
aynı verilerdeki istatistikleri (olmadan ) güncellerken farklı sayıda histogram adımı alabilmenizdir . Bunu pratikte hiç gözlemlemedim ama neden mümkün olmadığını anlamıyorum.
İstatistiklerin zaman içinde nasıl değiştiğini görmek için basit veriler üzerinde birkaç test yapalım. Aşağıda, bir tabloya sıralı tamsayılar eklemek, her bir eklemeden sonra istatistikleri toplamak ve istatistikler hakkında bir sonuç tablosuna bilgi kaydetmek için yazdığım bazı test kodu bulunmaktadır. 10000'e kadar bir seferde sadece 1 satır yerleştirerek başlayalım. Test yatağı:
DECLARE
@stats_id INT,
@table_object_id INT,
@rows_per_loop INT = 1,
@num_of_loops INT = 10000,
@loop_num INT;
BEGIN
SET NOCOUNT ON;
TRUNCATE TABLE X_STATS_RESULTS;
SET @table_object_id = OBJECT_ID ('X_SEQ_NUM');
SELECT @stats_id = stats_id FROM sys.stats
WHERE OBJECT_ID = @table_object_id
AND name = 'X_STATS_SEQ_INT_FULL';
SET @loop_num = 0;
WHILE @loop_num < @num_of_loops
BEGIN
SET @loop_num = @loop_num + 1;
INSERT INTO X_SEQ_NUM WITH (TABLOCK)
SELECT @rows_per_loop * (@loop_num - 1) + N FROM dbo.GetNums(@rows_per_loop);
UPDATE STATISTICS X_SEQ_NUM X_STATS_SEQ_INT_FULL WITH FULLSCAN; -- can comment out FULLSCAN as needed
INSERT INTO X_STATS_RESULTS WITH (TABLOCK)
SELECT 'X_STATS_SEQ_INT_FULL', @rows_per_loop * @loop_num, rows_sampled, steps
FROM sys.dm_db_stats_properties(@table_object_id, @stats_id);
END;
END;
Bu veriler için histogram adımlarının sayısı hızla 200'e yükselir (önce 397 satırlı maksimum adım sayısını vurur), 1485 satır tabloya gelene kadar 199 veya 200'de kalır, sonra histogram sadece 3 veya 4 olana kadar yavaşça azalır. adımları tekrarlayın. İşte tüm verilerin bir grafiği:
İşte histogram 10k satırlara benziyor:
RANGE_HI_KEY RANGE_ROWS EQ_ROWS DISTINCT_RANGE_ROWS AVG_RANGE_ROWS
1 0 1 0 1
9999 9997 1 9997 1
10000 0 1 0 1
Histogramın sadece 3 adımı olması bir problem mi? Bilgi bizim açımızdan korunmuş gibi görünüyor. Veri türü bir INTEGER olduğundan, 1 - 10000 arasındaki her tamsayı için tabloda kaç satır bulunduğunu anlayabiliriz. . Bunun bir örneği için bu SE yayınına bakın .
Tablodan tek bir satırı silip istatistikleri güncellersek ne olacağını düşünüyorsunuz? İdeal olarak, eksik tamsayının artık tabloda olmadığını göstermek için başka bir histogram adımı alacağız.
DELETE FROM X_SEQ_NUM
WHERE X_NUM = 1000;
UPDATE STATISTICS X_SEQ_NUM X_STATS_SEQ_INT_FULL WITH FULLSCAN;
DBCC SHOW_STATISTICS ('X_SEQ_NUM', 'X_STATS_SEQ_INT_FULL'); -- still 3 steps
DELETE FROM X_SEQ_NUM
WHERE X_NUM IN (2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000);
UPDATE STATISTICS X_SEQ_NUM X_STATS_SEQ_INT_FULL WITH FULLSCAN;
DBCC SHOW_STATISTICS ('X_SEQ_NUM', 'X_STATS_SEQ_INT_FULL'); -- still 3 steps
Bu biraz hayal kırıklığı yaratıyor. El ile bir histogram oluştursaydık, eksik olan her değer için bir adım eklerdik. SQL Server genel amaçlı bir algoritma kullanıyor, bu nedenle bazı veri kümeleri için kullandığı koddan daha uygun bir histogram bulabiliriz. Tabii ki, bir tablodan 0 veya 1 satır almak arasındaki pratik fark çok küçük. Her tamsayı tabloda 2 satır olan 20000 satır ile test ederken aynı sonuçları alıyorum. Verileri sildiğimde histogram adım atmıyor.
RANGE_HI_KEY RANGE_ROWS EQ_ROWS DISTINCT_RANGE_ROWS AVG_RANGE_ROWS
1 0 2 0 1
9999 19994 2 9997 2
10000 0 2 0 1
Tabloda 100 satır bulunan her tamsayı ile 1 milyon satırla test edersem, biraz daha iyi sonuçlar alırım, ancak yine de elle daha iyi bir histogram oluşturabilirim.
truncate table X_SEQ_NUM;
BEGIN TRANSACTION;
INSERT INTO X_SEQ_NUM WITH (TABLOCK)
SELECT N FROM dbo.GetNums(10000);
GO 100
COMMIT TRANSACTION;
UPDATE STATISTICS X_SEQ_NUM X_STATS_SEQ_INT_FULL WITH FULLSCAN;
DBCC SHOW_STATISTICS ('X_SEQ_NUM', 'X_STATS_SEQ_INT_FULL'); -- 4 steps
DELETE FROM X_SEQ_NUM
WHERE X_NUM = 1000;
UPDATE STATISTICS X_SEQ_NUM X_STATS_SEQ_INT_FULL WITH FULLSCAN;
DBCC SHOW_STATISTICS ('X_SEQ_NUM', 'X_STATS_SEQ_INT_FULL'); -- now 5 steps with a RANGE_HI_KEY of 998 (?)
DELETE FROM X_SEQ_NUM
WHERE X_NUM IN (2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000);
UPDATE STATISTICS X_SEQ_NUM X_STATS_SEQ_INT_FULL WITH FULLSCAN;
DBCC SHOW_STATISTICS ('X_SEQ_NUM', 'X_STATS_SEQ_INT_FULL'); -- still 5 steps
Son histogram:
RANGE_HI_KEY RANGE_ROWS EQ_ROWS DISTINCT_RANGE_ROWS AVG_RANGE_ROWS
1 0 100 0 1
998 99600 100 996 100
3983 298100 100 2981 100
9999 600900 100 6009 100
10000 0 100 0 1
Sıralı tamsayılarla ancak tabloda daha fazla satırla test edelim. Manuel olarak bir örnek boyutu belirtmek için çok küçük olan tabloların herhangi bir etkisi olmayacağına dikkat edin, bu yüzden her eke 100 satır ekleyeceğim ve her seferinde 1 milyon satıra kadar istatistik toplayacağım. Daha önce olduğu gibi benzer bir desen görüyorum, ancak tablodaki 637300 satıra ulaştığımda, tablodaki satırların% 100'ünü artık varsayılan örnekleme oranıyla örneklemiyorum. Satırları kazandıkça histogram adımlarının sayısı artar. Belki de bunun nedeni, SQL Server'ın tablodaki örneklenmemiş satırların sayısı arttıkça verilerde daha fazla boşluk bulunmasıdır. 1 M satırlarında bile 200 adım atmadım, ancak satır eklemeye devam etsem, oraya gidip sonunda geri dönmeye başlayacağımı umuyorum.
X ekseni tablodaki satır sayısıdır. Sıra sayısı arttıkça, örneklenen sıralar biraz değişir ve 650k'nin üzerine çıkmaz.
Şimdi VARCHAR verileri ile bazı basit testler yapalım.
CREATE TABLE X_SEQ_STR (X_STR VARCHAR(5));
CREATE STATISTICS X_SEQ_STR ON X_SEQ_STR(X_STR);
Burada NULL ile birlikte 200 sayı (dize olarak) ekliyorum.
INSERT INTO X_SEQ_STR
SELECT N FROM dbo.GetNums(200)
UNION ALL
SELECT NULL;
UPDATE STATISTICS X_SEQ_STR X_SEQ_STR ;
DBCC SHOW_STATISTICS ('X_SEQ_STR', 'X_SEQ_STR'); -- 111 steps, RANGE_ROWS is 0 or 1 for all steps
Tabloda bulunduğunda NULL değerinin her zaman kendi histogram adımını aldığını unutmayın. SQL Server bana tüm bilgileri korumak için tam olarak 201 adımlar verebilirdi ama bunu yapmadı. Teknik olarak bilgi kaybedilir çünkü '1111', '1' ve '2' arasında sıralar.
Şimdi sadece tamsayılar yerine farklı karakterler eklemeyi deneyelim:
truncate table X_SEQ_STR;
INSERT INTO X_SEQ_STR
SELECT CHAR(10 + N) FROM dbo.GetNums(200)
UNION ALL
SELECT NULL;
UPDATE STATISTICS X_SEQ_STR X_SEQ_STR ;
DBCC SHOW_STATISTICS ('X_SEQ_STR', 'X_SEQ_STR'); -- 95 steps, RANGE_ROWS is 0 or 1 or 2
Son testten gerçek bir fark yok.
Şimdi karakter eklemeyi deneyelim, ancak her karakterin farklı sayılarını tabloya koymayı deneyelim. Örneğin CHAR(11)
, 1 satırı CHAR(12)
vardır, 2 satırı vardır, vb.
truncate table X_SEQ_STR;
DECLARE
@loop_num INT;
BEGIN
SET NOCOUNT ON;
SET @loop_num = 0;
WHILE @loop_num < 200
BEGIN
SET @loop_num = @loop_num + 1;
INSERT INTO X_SEQ_STR WITH (TABLOCK)
SELECT CHAR(10 + @loop_num) FROM dbo.GetNums(@loop_num);
END;
END;
UPDATE STATISTICS X_SEQ_STR X_SEQ_STR ;
DBCC SHOW_STATISTICS ('X_SEQ_STR', 'X_SEQ_STR'); -- 148 steps, most with RANGE_ROWS of 0
Daha önce olduğu gibi hala tam 200 histogram adımı alamıyorum. Ancak, adımların çoğunda RANGE_ROWS
0 vardır.
Son test için, her bir döngüye rastgele bir 5 karakter dizesi ekleyeceğim ve her seferinde istatistik toplayacağım. İşte rastgele dize kodu:
char((rand()*25 + 65))+char((rand()*25 + 65))+char((rand()*25 + 65))+char((rand()*25 + 65))+char((rand()*25 + 65))
İşte tablodaki histogram adımları vs satırlarının grafiği:
Adım sayısının yukarı ve aşağı gitmeye başladığında 100'ün altına düşmediğini unutmayın. Bir yerden duydum (ancak şu anda kaynak yapamıyorum) SQL Server histogram oluşturma algoritması, onlar için oda bittiğinde histogram adımlarını birleştiriyor. Böylece, sadece küçük bir veri ekleyerek adım sayısında ciddi değişiklikler yapabilirsiniz. İşte ilginç bulduğum verilerin bir örneği:
ROWS_IN_TABLE ROWS_SAMPLED STEPS
36661 36661 133
36662 36662 143
36663 36663 143
36664 36664 141
36665 36665 138
İle örnekleme yaparken bile FULLSCAN
, tek bir satır eklemek adım sayısını 10 artırabilir, sabit tutabilir, sonra 2 azaltabilir, sonra 3 azaltabilir.
Tüm bunlardan ne özetleyebiliriz? Bunların hiçbirini kanıtlayamıyorum, ancak bu gözlemler doğru görünüyor:
- SQL Server, histogramları oluşturmak için genel bir kullanım algoritması kullanır. Bazı veri dağıtımları için verilerin elle daha eksiksiz bir temsilini oluşturmak mümkün olabilir.
- Tabloda NULL veri varsa ve istatistik sorgusu bunu bulursa, NULL veriler her zaman kendi histogram adımını alır.
- Tabloda bulunan minimum değer
RANGE_ROWS
= 0 ile kendi histogram adımını alır .
- Tabloda bulunan maksimum değer tablodaki son değer olacaktır
RANGE_HI_KEY
.
- SQL Server daha fazla veri örnekledikçe, bulduğu yeni verilere yer açmak için mevcut adımları birleştirmek gerekebilir. Yeterli histograma bakarsanız,
DISTINCT_RANGE_ROWS
veya için ortak değerlerin tekrarlandığını görebilirsiniz RANGE_ROWS
. Örneğin, 255, son test senaryosu için RANGE_ROWS
ve DISTINCT_RANGE_ROWS
burada bir sürü kez gösterilir .
- Basit veri dağıtımları için SQL Server'ın sıralı verileri hiçbir bilgi kaybına neden olmayan bir histogram adımında birleştirdiğini görebilirsiniz. Ancak verilere boşluklar eklerken histogram umduğunuz şekilde ayarlanmayabilir.
Bütün bunlar ne zaman sorun oluyor? Sorgu iyileştiricisinin iyi kararlar vermesi için veri dağıtımını temsil edemeyen bir histogram nedeniyle bir sorgunun kötü performans göstermesi bir sorundur. SQL Server milyonlarca veya daha fazla satırda bir histogram oluşturduğunda, ancak tam olarak 200 veya 201 histogram adımı kullanmadığında, daha fazla histogram adımına sahip olmanın her zaman daha iyi olduğunu ve konstrüksiyon olduğunu düşünme eğilimi olduğunu düşünüyorum. Ancak, histogramın 200 veya 201 adımı olsa bile çok sayıda istatistik problemi gördüm. SQL Server'ın bir istatistik nesnesi için oluşturduğu histogram adımlarının sayısı üzerinde herhangi bir kontrole sahip değiliz, bu yüzden endişelenmeyeceğim. Ancak, istatistik sorunlarından kaynaklanan düşük performans gösteren sorgularla karşılaştığınızda atabileceğiniz bazı adımlar vardır. Son derece kısa bir genel bakış sunacağım.
İstatistikleri tam olarak toplamak bazı durumlarda yardımcı olabilir. Çok büyük tablolar için, otomatik örnek boyutu tablodaki satırların% 1'inden az olabilir. Bazen bu, sütundaki veri bozulmasına bağlı olarak kötü planlara yol açabilir. Microsofts'un CREATE STATISTICS ve UPDATE STATISTICS ile ilgili belgeleri şöyle diyor:
ÖRNEK, varsayılan örneklemeye dayalı sorgu planının optimal olmadığı özel durumlar için kullanışlıdır. Çoğu durumda, sorgu optimize edici zaten örnekleme kullandığından ve yüksek kaliteli sorgu planları oluşturmak için gerektiğinde varsayılan olarak istatistiksel olarak anlamlı örnek boyutunu belirlediğinden ÖRNEK belirtmek gerekli değildir.
Çoğu iş yükü için tam tarama gerekmez ve varsayılan örnekleme yeterlidir. Ancak, çok çeşitli veri dağıtımlarına duyarlı bazı iş yükleri, daha fazla örnek boyutu veya hatta tam bir tarama gerektirebilir.
Bazı durumlarda filtrelenmiş istatistikler oluşturmak yardımcı olabilir. Eğri veriler ve birçok farklı değer içeren bir sütununuz olabilir. Verilerde yaygın olarak filtrelenen belirli değerler varsa, yalnızca bu ortak değerler için bir istatistik histogramı oluşturabilirsiniz. Sorgu iyileştirici, tüm sütun değerlerinde tanımlanan istatistikler yerine daha küçük bir veri aralığında tanımlanan istatistikleri kullanabilir. Histogramda hala 200 adım alamayacağınız garanti edilmez, ancak filtrelenmiş istatistikleri yalnızca bir değerde oluşturursanız, bu değerin bir histogramı adım atarsınız.
Bölümlenmiş bir görünüm kullanmak, tablo için 200'den fazla adım etkili bir şekilde elde etmenin bir yoludur. Büyük bir masayı yılda bir masaya kolayca bölebileceğinizi varsayalım. UNION ALL
Tüm yıllık tabloları birleştiren bir görünüm oluşturursunuz . Her tablonun kendi histogramı olacaktır. SQL Server 2014'te sunulan yeni artımlı istatistiklerin yalnızca istatistik güncellemelerinin daha verimli olmasına izin verdiğini unutmayın. Sorgu iyileştirici, bölüm başına oluşturulan istatistikleri kullanmaz.
Burada yapılabilecek çok daha fazla test var, bu yüzden denemenizi öneririz. Bu testi SQL Server 2014 express üzerinde yaptım, bu yüzden gerçekten sizi durduracak hiçbir şey yok.