İstatistik güncellemeleri için örnek boyutlarla garip davranış


25

SQL Server'daki (2012) istatistik güncellemeleriyle örnekleme eşiklerini araştırıyor ve bazı meraklı davranışlar farkettim. Temelde örneklenen satırların sayısı, bazı durumlarda - aynı veri grubuyla bile - değişebilir gibi görünüyor.

Bu sorguyu çalıştırıyorum:

--Drop table if exists
IF (OBJECT_ID('dbo.Test')) IS NOT NULL DROP TABLE dbo.Test;

--Create Table for Testing
CREATE TABLE dbo.Test(Id INT IDENTITY(1,1) CONSTRAINT PK_Test PRIMARY KEY CLUSTERED, TextValue VARCHAR(20) NULL);

--Insert enough data so we have more than 8Mb (the threshold at which sampling kicks in)
INSERT INTO dbo.Test(TextValue) 
SELECT TOP 1000000 'blahblahblah'
FROM sys.objects a, sys.objects b, sys.objects c, sys.objects d;  

--Create Index on TextValue
CREATE INDEX IX_Test_TextValue ON dbo.Test(TextValue);

--Update Statistics without specifying how many rows to sample
UPDATE STATISTICS dbo.Test IX_Test_TextValue;

--View the Statistics
DBCC SHOW_STATISTICS('dbo.Test', IX_Test_TextValue) WITH STAT_HEADER;

SHOW_STATISTICS'in çıktısına baktığımda, "Satırlar Örneklendi" nin her tam yürütme ile değiştiğini tespit ediyorum (yani, masa düştü, yeniden yaratıldı ve yeniden dolduruldu).

Örneğin:

Örneklenen Satırlar

  • 318618
  • 319240
  • 324198
  • 314154

Beklentim, bu rakamın, tablonun aynı olduğu her zaman aynı olmasıydı. Bu arada, sadece verileri silip tekrar yerleştirirsem bu davranışı alamam.

Bu kritik bir soru değil ama neler olup bittiğini anlamakla ilgileniyorum.


2
Eklediğiniz dosya grubundaki kaç dosya var? Ben 2016'da birkaç kez denedim ve iki kere tablo iki farklı numune 314712 ve 315270 idi ben testereyi boyutları 64 ile 3584 279 satırlarla sayfalarına ve 1 içine bölünmüş oldu - 279 her iki tam katları
Martin Smith

1
@JoeObbish - Her zaman AFAIK'ın tüm sayfalarını okur, bu yüzden şaşırmamıştım. Bazı nedenlerden dolayı, sorudaki sayıların bu modelle eşleşmediğini düşündüm. Ama yaptıkları matematiği yeniden yapmak. 318618 = 1142*279, 319240 = 1144*279 + 64,324198=1162*279 Ve 314154=1126bu yüzden varyans örneklenmiş sayfaların sayısıdır.
Martin Smith,

Bir dosya @MartinSmithJust - 279 rakamı yer kalıplarını anlamak için, her zamanki gibi ilginç
Matthew McGiffen

Yanıtlar:


26

Arka fon

İstatistikler nesnesine ilişkin veriler, aşağıdaki ifadeyi kullanarak toplanır:

SELECT 
    StatMan([SC0], [SC1], [SB0000]) 
FROM 
(
    SELECT TOP 100 PERCENT 
        [SC0], [SC1], STEP_DIRECTION([SC0]) OVER (ORDER BY NULL) AS [SB0000]
    FROM 
    (
        SELECT 
            [TextValue] AS [SC0], 
            [Id] AS [SC1] 
        FROM [dbo].[Test] 
            TABLESAMPLE SYSTEM (2.223684e+001 PERCENT) 
            WITH (READUNCOMMITTED) 
    ) AS _MS_UPDSTATS_TBL_HELPER 
    ORDER BY 
        [SC0], 
        [SC1], 
        [SB0000] 
) AS _MS_UPDSTATS_TBL
OPTION (MAXDOP 1)

Bu bildirimi Extended Events veya Profiler ( SP:StmtCompleted) ile toplayabilirsiniz .

İstatistik oluşturma sorguları, kümelenmemiş dizin sayfalarında doğal olarak oluşan değerlerin kümelenmesini önlemek için genellikle temel tabloya (kümelenmemiş bir dizin yerine) erişir.

Örneklenen satır sayısı, örnekleme için seçilen tam sayfa sayısına bağlıdır. Tablonun her sayfası seçilir veya seçilmez. Seçilen sayfalardaki tüm satırlar istatistiklere katkıda bulunur.

Rastgele numaralar

SQL Server, bir sayfanın uygun olup olmadığına karar vermek için rastgele bir sayı üreticisi kullanır. Bu örnekte kullanılan jeneratör , aşağıda gösterildiği gibi parametre değerlerine sahip Lehmer rasgele sayı üretecidir :

X sonraki = X tohum * 7 5 mod (2 31 - 1)

Değeri Xseed şu şekilde hesaplanır:

  • (Düşük tam sayı kısmı bigint) taban tablo partition_id, örneğin

    SELECT
        P.[partition_id] & 0xFFFFFFFF
    FROM sys.partitions AS P
    WHERE
        P.[object_id] = OBJECT_ID(N'dbo.Test', N'U')
        AND P.index_id = 1;
  • İçinde belirtilen değer REPEATABLE madde

    • Örneklenmiş için UPDATE STATISTICS için REPEATABLEdeğer 1'dir.
    • Bu değer, m_randomSeedörneğin erişim bayrağı 8666 etkinleştirildiğinde yürütme planlarında gösterilen erişim yönteminin dahili hata ayıklama bilgisinin öğesinde ortaya çıkar<Field FieldName="m_randomSeed" FieldValue="1" />

SQL Server 2012 için bu hesaplama sqlmin!UnOrderPageScanner::StartScan şöyle yapılır:

mov     edx,dword ptr [rcx+30h]
add     edx,dword ptr [rcx+2Ch]

nerede hafıza [rcx+30h] bölüm kimliğinin düşük 32 bitini içerir ve içindeki bellek kullanımdaki değeri [rcx+2Ch]içerir REPEATABLE.

Rasgele sayı üreteci daha sonra aynı yöntemde başlatılır, sqlmin!RandomNumGenerator::Init , komutun bulunduğu yer:

imul    r9d,r9d,41A7h

... tohumu, yukarıdaki denklemde gösterildiği gibi 41A7hex (16807 ondalık = 7 5 ) ile çarpar .

Daha sonra rastgele sayılar (tek tek sayfalar için), içine sıralanan aynı temel kod kullanılarak üretilir sqlmin!UnOrderPageScanner::SetupSubScanner.

StatMan

StatManYukarıda gösterilen örnek sorgu için, T-SQL ifadesinde olduğu gibi aynı sayfalar toplanacaktır:

SELECT 
    COUNT_BIG(*) 
FROM dbo.Test AS T 
    TABLESAMPLE SYSTEM (2.223684e+001 PERCENT)  -- Same sample %
    REPEATABLE (1)                              -- Always 1 for statman
    WITH (INDEX(0));                            -- Scan base object

Bu, çıktısı ile eşleşecektir:

SELECT 
    DDSP.rows_sampled
FROM sys.stats AS S
CROSS APPLY sys.dm_db_stats_properties(S.[object_id], S.stats_id) AS DDSP
WHERE 
    S.[object_id] = OBJECT_ID(N'dbo.Test', N'U')
    AND S.[name] = N'IX_Test_TextValue';

Kenar durumda

MINSTD Lehmer rasgele sayı üretecini kullanmanın bir sonucu, tohum değerlerinin sıfır ve int.max değerinin kullanılmaması gerektiğidir, çünkü algoritma bir sıfır dizisi üretecektir (her sayfayı seçerek).

Kod sıfır algılar ve bu durumda tohum olarak sistem 'saatinden bir değer kullanır. Tohum int.max ise ( 0x7FFFFFFF= 2 31) aynısını yapmaz - 1) aynı değildir.

İlk tohum, bölüm kimliğinin düşük 32 bitinin ve REPEATABLEdeğerinin toplamı olarak hesaplandığından bu senaryoyu yapabiliriz . REPEATABLEÖrnektir için int.max ve bu nedenle her sayfa olmak tohum sonuçlanacaktır değeri seçildiği:

SELECT
    0x7FFFFFFF - (P.[partition_id] & 0xFFFFFFFF)
FROM sys.partitions AS P
WHERE
    P.[object_id] = OBJECT_ID(N'dbo.Test', N'U')
    AND P.index_id = 1;

Bunu eksiksiz bir örnekle çalışmak:

DECLARE @SQL nvarchar(4000) = 
    N'
    SELECT
        COUNT_BIG(*) 
    FROM dbo.Test AS T 
        TABLESAMPLE (0 PERCENT) 
        REPEATABLE (' +
        (
            SELECT TOP (1)
                CONVERT(nvarchar(11), 0x7FFFFFFF - P.[partition_id] & 0xFFFFFFFF)
            FROM sys.partitions AS P
            WHERE
                P.[object_id] = OBJECT_ID(N'dbo.Test', N'U')
                AND P.index_id = 1
        ) + ')
        WITH (INDEX(0));';

PRINT @SQL;
--EXECUTE (@SQL);

Bu, TABLESAMPLEcümlede ne olursa olsun her sayfada her satırı seçecektir (yüzde sıfır).


11

Bu mükemmel bir soru! Kesin olarak bildiklerimle başlayacağım ve sonra spekülasyona geçeceğim. Blogumda bununla ilgili bir sürü detay var .

Örneklenen istatistikler güncellemeleri TABLESAMPLEsahne arkasında kullanılır . Bu konuda çevrimiçi belgeleri bulmak oldukça kolaydır. Ancak, TABLESAMPLEkısmen döndürülen satırların hobt_idnesneye kısmen bağlı olduğu bilinmediğine inanıyorum . Nesneyi bırakıp yeniden yarattığınızda yeni birhobt_id böylece rastgele örneklemeyle döndürülen satırlar farklı olur.

Verileri silip yeniden yerleştirirseniz, hobt_id , aynı kalır. Veriler diskte aynı şekilde verildiği sürece (bir tahsisat sırası taraması aynı sırayla aynı sonuçları verir), örneklenen verilerin değişmemesi gerekir.

Ayrıca, tablodaki kümelenmiş dizini yeniden oluşturarak örneklenen satır sayısını da değiştirebilirsiniz. Örneğin:

UPDATE STATISTICS dbo.Test IX_Test_TextValue;

DBCC SHOW_STATISTICS('dbo.Test', IX_Test_TextValue) WITH STAT_HEADER; -- 273862 rows

ALTER INDEX PK_Test on Test REBUILD;

UPDATE STATISTICS dbo.Test IX_Test_TextValue;

DBCC SHOW_STATISTICS('dbo.Test', IX_Test_TextValue) WITH STAT_HEADER; -- 273320 rows

Bunun neden olduğuna göre, SQL Server'ın bir dizinde örneklenmiş istatistikleri toplarken kümelenmemiş dizini yerine kümelenmiş dizini taraması nedeniyle olduğuna inanıyorum. Ben de bir (gizli istatistik güncelleme sorguları izleme bizlere) değerini gizli var olduğunu düşünüyorum REPEATABLEile kullanılabilir TABLESAMPLE. Bunların hiçbirini ispatlamamıştım, ancak histogramınızın ve satır örneklemenizin kümelenmiş dizinin yeniden oluşturulmasıyla neden değiştiğini açıklıyor.


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.