डेट रेंज को पुनः प्राप्त करने का सबसे कुशल तरीका


16

इस तरह की तालिका संरचना के साथ तिथि सीमा प्राप्त करने का सबसे कुशल तरीका क्या है?

create table SomeDateTable
(
    id int identity(1, 1) not null,
    StartDate datetime not null,
    EndDate datetime not null
)
go

कहते हैं कि तुम दोनों के लिए एक सीमा चाहते हैं StartDateऔर EndDate। तो दूसरे शब्दों में, अगर StartDateबीच में पड़ता है @StartDateBeginऔर @StartDateEnd, और EndDateके बीच में पड़ता है @EndDateBeginऔर @EndDateEndहै, तो कुछ करना।

मुझे पता है कि शायद इस बारे में कुछ तरीके हैं, लेकिन सबसे अधिक सलाह क्या है?

जवाबों:


29

यह सामान्य रूप से हल करने के लिए एक कठिन समस्या है, लेकिन कुछ चीजें हैं जो हम आशावादी को एक योजना चुनने में मदद करने के लिए कर सकते हैं। इस लिपि में 10,000 पंक्तियों के साथ एक तालिका बनाई गई है जिसमें पंक्तियों के ज्ञात छद्म यादृच्छिक वितरण के साथ वर्णन करना है:

CREATE TABLE dbo.SomeDateTable
(
    Id          INTEGER IDENTITY(1, 1) PRIMARY KEY NOT NULL,
    StartDate   DATETIME NOT NULL,
    EndDate     DATETIME NOT NULL
);
GO
SET STATISTICS XML OFF
SET NOCOUNT ON;
DECLARE
    @i  INTEGER = 1,
    @s  FLOAT = RAND(20120104),
    @e  FLOAT = RAND();

WHILE @i <= 10000
BEGIN
    INSERT dbo.SomeDateTable
        (
        StartDate, 
        EndDate
        )
    VALUES
        (
        DATEADD(DAY, @s * 365, {d '2009-01-01'}),
        DATEADD(DAY, @s * 365 + @e * 14, {d '2009-01-01'})
        )

    SELECT
        @s = RAND(),
        @e = RAND(),
        @i += 1
END

पहला सवाल यह है कि इस तालिका को कैसे अनुक्रमित किया जाए। एक विकल्प DATETIMEकॉलम पर दो इंडेक्स प्रदान करना है, इसलिए ऑप्टिमाइज़र कम से कम यह चुन सकता है कि उसे तलाश करना है StartDateया नहीं EndDate

CREATE INDEX nc1 ON dbo.SomeDateTable (StartDate, EndDate)
CREATE INDEX nc2 ON dbo.SomeDateTable (EndDate, StartDate)

स्वाभाविक रूप से, दोनों पर असमानताएं हैं StartDateऔर EndDateइसका मतलब है कि प्रत्येक सूचकांक में केवल एक स्तंभ उदाहरण क्वेरी में किसी खोज का समर्थन कर सकता है, लेकिन यह सबसे अच्छा है जो हम कर सकते हैं। हम INCLUDEएक कुंजी के बजाय प्रत्येक सूचकांक में दूसरा स्तंभ बनाने पर विचार कर सकते हैं, लेकिन हमारे पास अन्य प्रश्न हो सकते हैं जो अग्रणी स्तंभ पर एक समानता की तलाश कर सकते हैं और दूसरे कॉलम पर एक असमानता की तलाश कर सकते हैं। साथ ही, हमें इस तरह से बेहतर आंकड़े मिल सकते हैं। वैसे भी ...

DECLARE
    @StartDateBegin DATETIME = {d '2009-08-01'},
    @StartDateEnd DATETIME = {d '2009-10-15'},
    @EndDateBegin DATETIME = {d '2009-08-05'},
    @EndDateEnd DATETIME = {d '2009-10-22'}

SELECT
    COUNT_BIG(*)
FROM dbo.SomeDateTable AS sdt
WHERE
    sdt.StartDate BETWEEN @StartDateBegin AND @StartDateEnd
    AND sdt.EndDate BETWEEN @EndDateBegin AND @EndDateEnd

यह क्वेरी चर का उपयोग करती है, इसलिए सामान्य तौर पर ऑप्टिमाइज़र चयनात्मकता और वितरण पर अनुमान लगाएगा, जिसके परिणामस्वरूप 81 पंक्तियों का एक कार्डिनैलिटी अनुमान है । वास्तव में, क्वेरी 2076 पंक्तियों का उत्पादन करती है, एक विसंगति जो अधिक जटिल उदाहरण में महत्वपूर्ण हो सकती है।

एसक्यूएल सर्वर 2008 SP1 CU5 या बाद में (या आर 2 आरटीएम CU1) पर हम का लाभ ले सकते पैरामीटर एम्बेडिंग अनुकूलन बेहतर अनुमान प्राप्त करने के लिए, बस जोड़कर OPTION (RECOMPILE)करने के लिए SELECTऊपर क्वेरी। यह बैच निष्पादित होने से ठीक पहले एक संकलन का कारण बनता है, जिससे SQL सर्वर वास्तविक पैरामीटर मानों को 'देख' सकता है और उन के लिए अनुकूलन कर सकता है। इस परिवर्तन के साथ, अनुमान 468 पंक्तियों में सुधार होता है (हालांकि आपको यह देखने के लिए रनटाइम योजना की जांच करने की आवश्यकता है)। यह अनुमान 81 पंक्तियों से बेहतर है, लेकिन फिर भी यह सब करीब नहीं है। ट्रेस ध्वज 2301 द्वारा सक्षम किए गए मॉडलिंग एक्सटेंशन कुछ मामलों में मदद कर सकते हैं, लेकिन इस क्वेरी के साथ नहीं।

समस्या यह है कि दो रेंजों द्वारा योग्य पंक्तियाँ ओवरलैप खोजती हैं। ऑप्टिमाइज़र की लागत और कार्डिनैलिटी आकलन घटक में किए गए सरल अनुमानों में से एक यह है कि विधेय स्वतंत्र हैं (इसलिए यदि दोनों में 50% की चयनात्मकता है, तो दोनों को लागू करने का परिणाम 50% = 25% पंक्तियों का 50% अर्हता प्राप्त करने के लिए माना जाता है। )। जहाँ इस तरह का सहसंबंध एक समस्या है, हम अक्सर इसके चारों ओर मल्टी-कॉलम और / या फ़िल्टर्ड आँकड़ों के साथ काम कर सकते हैं। अज्ञात प्रारंभ और अंत बिंदुओं वाली दो श्रेणियों के साथ, यह अव्यावहारिक हो जाता है। यह वह जगह है जहाँ हमें कभी-कभी क्वेरी का पुनर्लेखन करने के लिए एक ऐसे फॉर्म का सहारा लेना पड़ता है जो एक बेहतर अनुमान उत्पन्न करता है:

SELECT COUNT(*) FROM
(
    SELECT
        sdt.Id
    FROM dbo.SomeDateTable AS sdt
    WHERE 
        sdt.StartDate BETWEEN @StartDateBegin AND @StartDateEnd
    INTERSECT
    SELECT
        sdt.Id
    FROM dbo.SomeDateTable AS sdt 
    WHERE
        sdt.EndDate BETWEEN @EndDateBegin AND @EndDateEnd
) AS intersected (id)
OPTION (RECOMPILE)

यह फॉर्म 2110 पंक्तियों (2076 वास्तविक बनाम) के रनटाइम अनुमान का उत्पादन करने के लिए होता है। जब तक आपके पास TF 2301 है, जिस स्थिति में अधिक उन्नत मॉडलिंग तकनीक चाल के माध्यम से देखते हैं और पहले की तरह ही अनुमान लगाते हैं: 463 पंक्तियाँ।

एक दिन SQL सर्वर अंतराल के लिए मूल समर्थन प्राप्त कर सकता है। यदि यह अच्छे सांख्यिकीय समर्थन के साथ आता है, तो डेवलपर्स इस तरह से ट्यूनिंग क्वेरी योजनाओं को थोड़ा कम कर सकते हैं।


5

मैं एक ऐसे समाधान को नहीं जानता जो सभी डेटा वितरण के लिए तेज़ है, लेकिन यदि आपकी सभी सीमाएँ कम हैं, तो हम आमतौर पर इसे गति दे सकते हैं। यदि, उदाहरण के लिए, इस क्वेरी के बजाय सीमाएँ एक दिन से छोटी हैं, तो:

SELECT  TaskId ,    
        TaskDescription ,
        StartedAt ,    
        FinishedAt    
FROM    dbo.Tasks    
WHERE   '20101203' BETWEEN StartedAt AND FinishedAt

हम एक और शर्त जोड़ सकते हैं:

SELECT  TaskId ,    
        TaskDescription ,
        StartedAt ,    
        FinishedAt    
FROM    dbo.Tasks    
WHERE   '20101203' BETWEEN StartedAt AND FinishedAt
    AND StartedAt >= '20101202'
    AND FinishedAt <= '20101204' ;

परिणामस्वरूप, पूरी तालिका को स्कैन करने के बजाय क्वेरी केवल दो दिनों की रेंज स्कैन करेगी, जो तेज है। यदि सीमाएं लंबी हो सकती हैं, तो हम उन्हें छोटे लोगों के अनुक्रम के रूप में संग्रहीत कर सकते हैं। यहाँ विवरण: बाधाओं की मदद से ट्यूनिंग SQL क्वेरी

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