आँकड़ों के अद्यतन के लिए नमूना आकार के साथ अजीब व्यवहार


25

मैं SQL सर्वर (2012) पर आँकड़ों के अद्यतन के साथ नमूने थ्रेसहोल्ड की जाँच के आसपास खेल रहा हूँ और कुछ उत्सुक व्यवहार को देखा। मूल रूप से नमूने की पंक्तियों की संख्या कुछ परिस्थितियों में भिन्न होती है - यहां तक ​​कि डेटा के समान सेट के साथ भी।

मैं इस प्रश्न को चलाता हूं:

--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 के आउटपुट को देखता हूं तो मुझे लगता है कि "Rows Sampled" प्रत्येक पूर्ण निष्पादन के साथ बदलता रहता है (यानी टेबल गिरा दिया जाता है, फिर से बनाया गया और फिर से बनाया गया)।

उदाहरण के लिए:

पंक्तियों का नमूना

  • 318,618
  • 319,240
  • 324,198
  • 314,154

मेरी उम्मीद यह थी कि यह आंकड़ा हर बार समान होगा क्योंकि तालिका समान है। वैसे, मुझे यह व्यवहार नहीं मिलता है अगर मैं सिर्फ डेटा हटाता हूं और इसे फिर से सम्मिलित करता हूं।

यह एक महत्वपूर्ण सवाल नहीं है, लेकिन मुझे यह समझने में दिलचस्पी होगी कि क्या हो रहा है।


2
आप जिस फ़ाइल समूह में सम्मिलित हो रहे हैं, उसमें कितनी फाइलें हैं? मैं 2016 को एक दो बार कोशिश की है और दोनों बार तालिका 279 पंक्तियों के साथ 3584 पृष्ठों और 1 64 के साथ दो अलग अलग नमूना आकार मैं देखा 314,712 और 315,270 थे में विभाजित था - के 279 दोनों सटीक गुणकों
मार्टिन स्मिथ

1
@ जोएबिश - यह हमेशा पूरे पृष्ठों को पढ़ता है इसलिए मैं इससे हैरान नहीं था। किसी कारण से मुझे लगा कि प्रश्न में संख्या हालांकि उस पैटर्न से मेल नहीं खाती। लेकिन गणित को फिर से करने के बाद वे करते हैं। 318618 = 1142*279, 319240 = 1144*279 + 64, 324198=1162*279और 314154=1126इतने विचरण नमूना पृष्ठों की संख्या है।
मार्टिन स्मिथ

@MartinSmithJust एक फ़ाइल - 279 का आंकड़ा दिलचस्प है, मैं हमेशा शामिल पैटर्न को समझना पसंद करता हूं
मैथ्यू मैकफिनन

जवाबों:


26

पृष्ठभूमि

आंकड़े ऑब्जेक्ट के लिए डेटा फॉर्म के एक बयान का उपयोग करके इकट्ठा किए जाते हैं:

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)

आप इस स्टेटमेंट को एक्सटेंडेड इवेंट्स या प्रोफाइलर ( SP:StmtCompleted) के साथ इकट्ठा कर सकते हैं ।

सांख्यिकी जेनरेशन क्वेरीज़ अक्सर बेस टेबल (नॉनक्लेस्टेड इंडेक्स के बजाय) को उन मूल्यों की क्लस्टरिंग से बचने के लिए एक्सेस करते हैं जो स्वाभाविक रूप से नॉनक्लेस्टेड इंडेक्स पेजों पर होते हैं।

नमूने की पंक्तियों की संख्या नमूने लेने के लिए चुने गए पूरे पृष्ठों की संख्या पर निर्भर करती है। तालिका का प्रत्येक पृष्ठ या तो चयनित है या यह नहीं है। चयनित पृष्ठों की सभी पंक्तियाँ आँकड़ों में योगदान करती हैं।

रैंडम नंबर

SQL सर्वर यह तय करने के लिए एक यादृच्छिक संख्या जनरेटर का उपयोग करता है कि पृष्ठ योग्य है या नहीं। इस उदाहरण में इस्तेमाल किया गया जनरेटर लीमर यादृच्छिक संख्या जनरेटर है जिसमें पैरामीटर मान नीचे दिखाए गए हैं:

X अगला = X बीज * 7 5 मॉड (2 31 - 1)

के मूल्य की गणना निम्न के योग के रूप में की जाती है:Xseed

  • निम्न bigintतालिका का पूर्णांक भाग ( ) बेस टेबल के partition_idउदा

    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;
  • REPEATABLEक्लॉज में निर्दिष्ट मूल्य

    • नमूना के लिए UPDATE STATISTICS, REPEATABLEमान 1 है।
    • m_randomSeedनिष्पादन मान में आंतरिक विधि डीबगिंग जानकारी के तत्व में यह मान उजागर होता है, जब ट्रेस ध्वज 8666 सक्षम होता है, उदाहरण के लिए<Field FieldName="m_randomSeed" FieldValue="1" />

SQL Server 2012 के लिए, यह गणना निम्न में होती है sqlmin!UnOrderPageScanner::StartScan:

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

जहाँ मेमोरी में [rcx+30h]विभाजन आईडी के कम 32 बिट्स [rcx+2Ch]होते हैं और मेमोरी REPEATABLEमें उपयोग में मूल्य होता है ।

यादृच्छिक संख्या जनरेटर को बाद में उसी तरीके से शुरू किया जाता है, कॉलिंग sqlmin!RandomNumGenerator::Init, जहां निर्देश:

imul    r9d,r9d,41A7h

... 41A7हेक्स द्वारा बीज को गुणा करता है (16807 दशमलव = 7 5 ) जैसा कि ऊपर समीकरण में दिखाया गया है।

बाद में यादृच्छिक संख्या (अलग-अलग पृष्ठों के लिए) एक ही मूल कोड का उपयोग करके उत्पन्न की जाती है sqlmin!UnOrderPageScanner::SetupSubScanner

StatMan

StatManऊपर दिखाए गए उदाहरण क्वेरी के लिए, टी-एसक्यूएल स्टेटमेंट के लिए उन्हीं पृष्ठों को एकत्र किया जाएगा:

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

यह निम्न के आउटपुट से मेल खाएगा:

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

किनारे का मामला

MINSTD लेहमर रैंडम नंबर जनरेटर का उपयोग करने का एक परिणाम यह है कि बीज मान शून्य और int.max का उपयोग नहीं किया जाना चाहिए क्योंकि यह एल्गोरिथ्म में जीरो के अनुक्रम (प्रत्येक पृष्ठ का चयन) का उत्पादन करेगा।

कोड शून्य का पता लगाता है, और उस स्थिति में बीज के रूप में सिस्टम 'क्लॉक' से एक मान का उपयोग करता है। यदि बीज int.max ( 0x7FFFFFFF= 2 31 - 1) है तो यह ऐसा नहीं करता है ।

हम इस परिदृश्य को इंजीनियर कर सकते हैं क्योंकि प्रारंभिक बीज की गणना विभाजन आईडी के कम 32 बिट्स और REPEATABLEमूल्य के योग के रूप में की जाती है । वह REPEATABLEमान जिसके परिणामस्वरूप बीज int.max होगा और इसलिए प्रत्येक पृष्ठ को नमूने के लिए चुना जा रहा है:

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;

एक पूर्ण उदाहरण में कार्य करना:

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

जो कि TABLESAMPLEक्लॉज (यहां तक ​​कि शून्य प्रतिशत) जो भी कहता है , हर पेज पर हर पंक्ति का चयन करेगा ।


11

यह एक अच्छा सवाल है! मुझे यकीन है कि मैं जो जानता हूं उसके साथ शुरू करूंगा और फिर अटकलों पर आगे बढ़ूंगा। मेरे ब्लॉग पोस्ट में इसके बारे में बहुत सारी जानकारी यहाँ दी गई है

सैंपल किए गए आँकड़े अपडेट TABLESAMPLEपर्दे के पीछे का उपयोग करते हैं। उस ऑनलाइन के बारे में प्रलेखन खोजना बहुत आसान है। हालाँकि, मेरा मानना ​​है कि यह अच्छी तरह से ज्ञात नहीं है कि पंक्तियाँ TABLESAMPLEआंशिक रूप hobt_idसे ऑब्जेक्ट पर निर्भर करती हैं । जब आप ड्रॉप करते हैं और ऑब्जेक्ट को नया hobt_idबनाते हैं तो रैंडम सैंपलिंग द्वारा लौटी पंक्तियाँ अलग होती हैं।

यदि आप डेटा को हटाते हैं और पुनर्निवेश करते हैं, hobt_idतो वही रहता है। जब तक डेटा को डिस्क पर उसी तरह से रखा जाता है (एक आवंटन आदेश स्कैन उसी क्रम में समान परिणाम देता है) तब तक नमूना डेटा को बदलना नहीं चाहिए।

आप तालिका पर क्लस्टर किए गए अनुक्रमणिका के पुनर्निर्माण द्वारा नमूना की गई पंक्तियों की संख्या भी बदल सकते हैं। उदाहरण के लिए:

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

जैसा कि ऐसा क्यों होता है, मेरा मानना ​​है कि यह इसलिए है क्योंकि एसक्यूएल सर्वर एक इंडेक्स पर सैंपल किए गए आंकड़ों को इकट्ठा करते समय गैर-अनुक्रमित इंडेक्स के बजाय क्लस्टर इंडेक्स को स्कैन करता है। मुझे यह भी लगता है कि वहाँ एक छिपा हुआ है (हम में से जो छिपा आँकड़े अद्यतन प्रश्नों का पता लगाने के लिए) मूल्य के REPEATABLEसाथ प्रयोग किया जाता है TABLESAMPLE। मैंने उसमें से कोई भी साबित नहीं किया है, लेकिन यह बताता है कि क्यों आपके हिस्टोग्राम और पंक्तियों ने क्लस्टर्ड इंडेक्स के पुनर्निर्माण के साथ बदलाव किए हैं।


3

मैं भूल गया कि प्रति पृष्ठ एक यादृच्छिक संभावना असाइन करने के संदर्भ में TABLESAMPLE ने कैसे काम किया। - मार्टिन स्मिथ

मैंने इसे Microsoft SQL Server 2008 के अंदर देखा : इटज़िक बेन-गण द्वारा टी-एसक्यूएल क्वेरी

यहाँ छवि विवरण दर्ज करें

Roji द्वारा TABLESAMPLE का उपयोग करके नमूना भी देखें । पी। थॉमस।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.