कास्ट टू डेट सरगेबल है लेकिन क्या यह एक अच्छा विचार है?


47

SQL Server 2008 में डेट डेटाइप जोड़ा गया था।

datetimeस्तंभ को कास्टिंग करना dateबहुत मुश्किल है और datetimeस्तंभ पर एक सूचकांक का उपयोग कर सकता है ।

select *
from T
where cast(DateTimeCol as date) = '20130101';

आपके पास दूसरा विकल्प इसके बजाय एक सीमा का उपयोग करना है।

select *
from T
where DateTimeCol >= '20130101' and
      DateTimeCol < '20130102'

क्या ये प्रश्न समान रूप से अच्छे हैं या एक को दूसरे पर पसंद किया जाना चाहिए?


4
निष्पादन योजना क्या कहती है?
a_horse_with_no_name

3
मैं यह ध्यान देने में मदद नहीं कर सकता कि LINQ2SQL where cast(date_column as date) = 'value'C # के समान प्रस्तुत करने पर SQL उत्पन्न करता है where obj.date_column.Date == date_variable
GSerg

6
यह एक उत्कृष्ट कनेक्ट आइटम है। :)
रॉब फ़र्ले

1
कनेक्ट साइट को विकिपीडिया में सर्गबल के साथ हटा दिया गया है
इवानजिन्हो

जवाबों:


59

कास्टिंग की तिथि के लिए अस्थिरता के पीछे के तंत्र को गतिशील तलाश कहा जाता है ।

SQL सर्वर GetRangeThroughConvertरेंज की शुरुआत और अंत प्राप्त करने के लिए एक आंतरिक फ़ंक्शन को कॉल करता है।

कुछ आश्चर्य की बात है कि यह आपके शाब्दिक मूल्यों के समान नहीं है।

प्रति पृष्ठ एक पंक्ति और प्रति दिन 1440 पंक्तियों के साथ एक तालिका बनाना

CREATE TABLE T
  (
     DateTimeCol DATETIME PRIMARY KEY,
     Filler      CHAR(8000) DEFAULT 'X'
  );

WITH Nums(Num)
     AS (SELECT number
         FROM   spt_values
         WHERE  type = 'P'
                AND number BETWEEN 1 AND 1440),
     Dates(Date)
     AS (SELECT {d '2012-12-30'} UNION ALL
         SELECT {d '2012-12-31'} UNION ALL
         SELECT {d '2013-01-01'} UNION ALL
         SELECT {d '2013-01-02'} UNION ALL
         SELECT {d '2013-01-03'})
INSERT INTO T
            (DateTimeCol)
SELECT DISTINCT DATEADD(MINUTE, Num, Date)
FROM   Nums,
       Dates 

फिर दौड़ रहा है

SET STATISTICS IO ON;
SET STATISTICS TIME ON;

SELECT *
FROM   T
WHERE  DateTimeCol >= '20130101'
       AND DateTimeCol < '20130102'

SELECT *
FROM   T
WHERE  CAST(DateTimeCol AS DATE) = '20130101'; 

पहली क्वेरी 1443पढ़ी है और दूसरी 2883तो यह एक पूरे अतिरिक्त दिन पढ़ रहा है तो एक अवशिष्ट विधेयकों के खिलाफ इसे त्यागने।

योजना से पता चलता है कि विधेय की तलाश है

Seek Keys[1]: Start: DateTimeCol > Scalar Operator([Expr1006]), 
               End: DateTimeCol < Scalar Operator([Expr1007])

तो इसके बजाय >= '20130101' ... < '20130102'यह पढ़ता है > '20121231' ... < '20130102'तो सभी 2012-12-31पंक्तियों को त्याग देता है ।

इस पर भरोसा करने का एक और नुकसान यह है कि पारंपरिक रेंज क्वेरी के साथ कार्डिनैलिटी का अनुमान उतना सटीक नहीं हो सकता है। यह आपके SQL फिडेल के संशोधित संस्करण में देखा जा सकता है ।

तालिका में सभी 100 पंक्तियाँ अब विधेय से मेल खाती हैं (उसी दिन सभी 1 मिनट के अलावा डेटेटाइम के साथ)।

दूसरी (श्रेणी) क्वेरी सही रूप से अनुमान लगाती है कि 100 मेल खाएगी और क्लस्टर इंडेक्स स्कैन का उपयोग करेगी। CAST( AS DATE)क्वेरी को गलत तरीके से अनुमान है कि केवल एक पंक्ति से मेल खाएगा और महत्वपूर्ण खोज के साथ एक योजना पैदा करता है।

आँकड़ों को पूरी तरह से नजरअंदाज नहीं किया जाता है। यदि तालिका की सभी पंक्तियों में समान है datetimeऔर यह विधेय (जैसे 20130101 00:00:00या 20130101 01:00:00) से मेल खाती है, तो योजना अनुमानित 31.6228 पंक्तियों के साथ एक संकुल सूचकांक स्कैन दिखाती है।

100 ^ 0.75 = 31.6228

तो उस स्थिति में यह प्रतीत होता है कि अनुमान यहाँ सूत्र से लिया गया है

यदि तालिका की सभी पंक्तियों में समान है datetimeऔर यह विधेय (जैसे 20130102 01:00:00) से मेल नहीं खाती है, तो यह 1 की अनुमानित पंक्ति संख्या और लुकअप के साथ योजना पर वापस आती है।

उन मामलों के लिए जहां तालिका में एक से अधिक DISTINCTमूल्य हैं, अनुमानित पंक्तियां वैसी ही लगती हैं जैसे कि क्वेरी बिल्कुल दिख रही थी 20130101 00:00:00

यदि आँकड़े हिस्टोग्राम होता है तो एक कदम होगा, 2013-01-01 00:00:00.000तो अनुमान के आधार पर होगा EQ_ROWS(यानी उस तिथि को अन्य समय को ध्यान में नहीं रखना)। अन्यथा यदि कोई कदम नहीं है तो ऐसा लगता है जैसे कि वह AVG_RANGE_ROWSआसपास के चरणों से उपयोग करता है ।

जैसा कि datetimeकई प्रणालियों में लगभग 3ms की सटीकता है, बहुत कम वास्तविक डुप्लिकेट मान होंगे और यह संख्या 1 होगी।


1
हाय मार्टिन, क्या आप TL;DRअलग-अलग मामलों के साथ कुछ बुलेट बिंदुओं के साथ एक हिस्सा जोड़ सकते हैं चाहे उस मामले में, यह करने के लिए कास्ट एक अच्छा विचार है या नहीं?
टीटी।

6
@TT। मुझे लगता है कि मुद्दा यह है कि यह एक अच्छा विचार नहीं है। आप एक विधि का उपयोग क्यों करना चाहते हैं जिसमें एक धोखा शीट की आवश्यकता होती है?
हारून बर्ट्रेंड

10

मुझे पता है कि यह मार्टिन से एक लंबे समय तक चलने वाला ग्रेट उत्तर है, लेकिन मैं यहां SQL सर्वर के नए संस्करणों में व्यवहार में कुछ बदलाव जोड़ना चाहता था। यह केवल 2008R2 तक परीक्षण किया गया प्रतीत होता है।

नए USE HINTs के साथ, जो कुछ कार्डिनैलिटी का अनुमान लगाने का समय यात्रा संभव बनाते हैं, हम देख सकते हैं कि चीजें कब बदली हैं।

SQL फिडेल के समान सेटअप का उपयोग करना।

CREATE TABLE T ( ID INT IDENTITY PRIMARY KEY, DateTimeCol DATETIME, Filler CHAR(8000) NULL );

CREATE INDEX IX_T_DateTimeCol ON T ( DateTimeCol );


WITH E00(N) AS (SELECT 1 UNION ALL SELECT 1),
     E02(N) AS (SELECT 1 FROM E00 a, E00 b),
     E04(N) AS (SELECT 1 FROM E02 a, E02 b),
     E08(N) AS (SELECT 1 FROM E04 a, E04 b),
     Num(N) AS (SELECT ROW_NUMBER() OVER (ORDER BY E08.N) FROM E08)
INSERT INTO T(DateTimeCol)
SELECT TOP 100 DATEADD(MINUTE, Num.N, '20130101')
FROM Num;

हम विभिन्न स्तरों का परीक्षण कर सकते हैं जैसे:

SELECT *
FROM   T
WHERE  CAST(DateTimeCol AS DATE) = '20130101'
OPTION ( USE HINT ( 'QUERY_OPTIMIZER_COMPATIBILITY_LEVEL_100' ));
GO

SELECT *
FROM   T
WHERE  CAST(DateTimeCol AS DATE) = '20130101'
OPTION ( USE HINT ( 'QUERY_OPTIMIZER_COMPATIBILITY_LEVEL_110' ));
GO 

SELECT *
FROM   T
WHERE  CAST(DateTimeCol AS DATE) = '20130101'
OPTION ( USE HINT ( 'QUERY_OPTIMIZER_COMPATIBILITY_LEVEL_120' ));
GO 

SELECT *
FROM   T
WHERE  CAST(DateTimeCol AS DATE) = '20130101'
OPTION ( USE HINT ( 'QUERY_OPTIMIZER_COMPATIBILITY_LEVEL_130' ));
GO 

SELECT *
FROM   T
WHERE  CAST(DateTimeCol AS DATE) = '20130101'
OPTION ( USE HINT ( 'QUERY_OPTIMIZER_COMPATIBILITY_LEVEL_140' ));
GO 

इन सभी की योजनाएँ यहाँ उपलब्ध हैं । सुसंगत स्तर 100 और 110 दोनों ही प्रमुख लुकअप योजना देते हैं, लेकिन हम 120 के स्तर के साथ शुरू करते हैं, हम 100 पंक्ति अनुमानों के साथ एक ही स्कैन योजना प्राप्त करना शुरू करते हैं। यह कॉम्पिटिटर स्तर 140 तक सच है।

पागल

पागल

पागल

>= '20130101', < '20130102'योजनाओं के लिए कार्डिनैलिटी का अनुमान 100 पर बना हुआ है, जो अपेक्षित था।

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