2008-08-05 12 views
75

यहां मैं उपयोग करता हूं:डेटाटाइम वैल्यू (एसक्यूएल सर्वर) के समय हिस्से को कैसे हटाएं?

SELECT CAST(FLOOR(CAST(getdate() as FLOAT)) as DATETIME) 

मुझे लगता है कि एक बेहतर और अधिक सुरुचिपूर्ण तरीका हो सकता है।

आवश्यकताएं:

  • इसे जितनी जल्दी हो सके (कम कास्टिंग, बेहतर) होना चाहिए।
  • अंतिम परिणाम एक datetime प्रकार होना चाहिए, स्ट्रिंग नहीं।

उत्तर

103

एसक्यूएल सर्वर 2008 और ऊपर

एसक्यूएल सर्वर 2008 में और ऊपर, बेशक सबसे तेज़ तरीका Convert(date, @date) है। यदि आवश्यक हो तो इसे datetime या datetime2 पर वापस डाला जा सकता है।

SQL सर्वर 2005 और पुराने में वास्तव में सर्वश्रेष्ठ क्या है?

मैंने एसक्यूएल सर्वर में किसी तारीख से समय को कम करने के लिए सबसे तेज़ क्या है, इसके बारे में असंगत दावों को देखा है, और कुछ लोगों ने यह भी कहा कि उन्होंने परीक्षण किया है, लेकिन मेरा अनुभव अलग-अलग रहा है। तो आइए कुछ और कड़े परीक्षण करें और सभी को स्क्रिप्ट दें ताकि अगर मैं कोई गलती करता हूं तो लोग मुझे सही कर सकते हैं।

फ्लोट रूपांतरण सटीक

पहले नहीं कर रहे हैं, मैं, float को datetime परिवर्तित करने से दूर रहना होगा क्योंकि इसे सही ढंग से नहीं बदलता। आप टाइम-हटाने की चीज़ को सही तरीके से करने से दूर हो सकते हैं, लेकिन मुझे लगता है कि इसका उपयोग करना एक बुरा विचार है क्योंकि यह स्पष्ट रूप से डेवलपर्स से संचार करता है कि यह एक सुरक्षित संचालन है और यह नहीं है।एक नज़र डालें:

declare @d datetime; 
set @d = '2010-09-12 00:00:00.003'; 
select Convert(datetime, Convert(float, @d)); 
-- result: 2010-09-12 00:00:00.000 -- oops 

ऐसा कुछ नहीं है जिसे हमें अपने कोड में या हमारे उदाहरणों में ऑनलाइन पढ़ाना चाहिए।

इसके अलावा, यह भी सबसे तेज़ तरीका नहीं है!

प्रमाण - निष्पादन परीक्षण

आप कुछ परीक्षण अपने आप को कैसे अलग अलग तरीकों वास्तव में टिके रहते हैं को देखने के लिए प्रदर्शन करने के लिए चाहते हैं, तो आप इस सेटअप स्क्रिप्ट परीक्षण आगे नीचे चलाने की आवश्यकता होगी:

create table AllDay (Tm datetime NOT NULL CONSTRAINT PK_AllDay PRIMARY KEY CLUSTERED); 
declare @d datetime; 
set @d = DateDiff(Day, 0, GetDate()); 
insert AllDay select @d; 
while @@ROWCOUNT != 0 
    insert AllDay 
    select * from (
     select Tm = 
     DateAdd(ms, (select Max(DateDiff(ms, @d, Tm)) from AllDay) + 3, Tm) 
     from AllDay 
    ) X 
    where Tm < DateAdd(Day, 1, @d); 
exec sp_spaceused AllDay; -- 25,920,000 rows 

कृपया ध्यान दें कि यह आपके डेटाबेस में 427.57   एमबी तालिका बनाता है और इसे चलाने के लिए 15-30 मिनट की तरह कुछ ले जाएगा। यदि आपका डेटाबेस छोटा है और 10% की वृद्धि पर सेट किया गया है तो इससे पहले कि आप पहले पर्याप्त आकार में हों, उससे अधिक समय लगेगा।

अब वास्तविक प्रदर्शन परीक्षण स्क्रिप्ट के लिए। कृपया ध्यान दें कि ग्राहकों को पंक्तियों को वापस नहीं करना उद्देश्यपूर्ण है क्योंकि यह 26 मिलियन पंक्तियों पर पागल महंगा है और विधियों के बीच प्रदर्शन अंतर को छिपाएगा।

प्रदर्शन परिणाम

set statistics time on; 
-- (All queries are the same on io: logical reads 54712) 
GO 
declare 
    @dd date, 
    @d datetime, 
    @di int, 
    @df float, 
    @dv varchar(10); 

-- Round trip back to datetime 
select @d = CONVERT(date, Tm) from AllDay; -- CPU time = 21234 ms, elapsed time = 22301 ms. 
select @d = CAST(Tm - 0.50000004 AS int) from AllDay; -- CPU = 23031 ms, elapsed = 24091 ms. 
select @d = DATEDIFF(DAY, 0, Tm) from AllDay; -- CPU = 23782 ms, elapsed = 24818 ms. 
select @d = FLOOR(CAST(Tm as float)) from AllDay; -- CPU = 36891 ms, elapsed = 38414 ms. 
select @d = CONVERT(VARCHAR(8), Tm, 112) from AllDay; -- CPU = 102984 ms, elapsed = 109897 ms. 
select @d = CONVERT(CHAR(8), Tm, 112) from AllDay; -- CPU = 103390 ms, elapsed = 108236 ms. 
select @d = CONVERT(VARCHAR(10), Tm, 101) from AllDay; -- CPU = 123375 ms, elapsed = 135179 ms. 

-- Only to another type but not back 
select @dd = Tm from AllDay; -- CPU time = 19891 ms, elapsed time = 20937 ms. 
select @di = CAST(Tm - 0.50000004 AS int) from AllDay; -- CPU = 21453 ms, elapsed = 23079 ms. 
select @di = DATEDIFF(DAY, 0, Tm) from AllDay; -- CPU = 23218 ms, elapsed = 24700 ms 
select @df = FLOOR(CAST(Tm as float)) from AllDay; -- CPU = 29312 ms, elapsed = 31101 ms. 
select @dv = CONVERT(VARCHAR(8), Tm, 112) from AllDay; -- CPU = 64016 ms, elapsed = 67815 ms. 
select @dv = CONVERT(CHAR(8), Tm, 112) from AllDay; -- CPU = 64297 ms, elapsed = 67987 ms. 
select @dv = CONVERT(VARCHAR(10), Tm, 101) from AllDay; -- CPU = 65609 ms, elapsed = 68173 ms. 
GO 
set statistics time off; 

कुछ पर्यटन विश्लेषण

कुछ इस बारे में नोट। सबसे पहले, अगर केवल ग्रुप बाय या तुलना कर रहे हैं, तो datetime पर वापस जाने की आवश्यकता नहीं है। तो आप इसे से बचकर कुछ सीपीयू को बचा सकते हैं, जब तक आपको प्रदर्शन उद्देश्यों के लिए अंतिम मूल्य की आवश्यकता न हो। तुम भी द्वारा अपरिवर्तित मूल्य ग्रुप और केवल SELECT खंड में रूपांतरण रख सकते हैं:

select Convert(datetime, DateDiff(dd, 0, Tm)) 
from (select '2010-09-12 00:00:00.003') X (Tm) 
group by DateDiff(dd, 0, Tm) 

इसके अलावा, देखते हैं कि कैसे सांख्यिक रूपांतरण केवल थोड़ा अधिक समय datetime वापस करने के लिए परिवर्तित करने के लिए ले, लेकिन varchar रूपांतरण लगभग दोगुना हो जाता है? यह सीपीयू के उस हिस्से को प्रकट करता है जो प्रश्नों में दिनांक गणना के लिए समर्पित है। सीपीयू उपयोग के कुछ हिस्सों में दिनांक गणना शामिल नहीं है, और यह उपरोक्त प्रश्नों में 19875   एमएस के करीब कुछ प्रतीत होता है। फिर रूपांतरण कुछ अतिरिक्त राशि लेता है, इसलिए यदि दो रूपांतरण होते हैं, तो वह राशि लगभग दो बार उपयोग की जाती है।

अधिक परीक्षा का पता चलता है Convert(, 112) की तुलना में, Convert(, 101) क्वेरी, (क्योंकि यह एक लंबे समय तक varchar? उपयोग करता है) के लिए कुछ अतिरिक्त सीपीयू खर्च किया है कि क्योंकि वापस date से पीछे नहीं रूपांतरण प्रारंभिक रूपांतरण के रूप में के रूप में ज्यादा खर्च नहीं करना पड़ता varchar को, लेकिन Convert(, 112) के साथ यह 20000   एमएस सीपीयू बेस लागत के करीब है।

यहाँ CPU समय है कि मैं उपरोक्त विश्लेषण के लिए इस्तेमाल किया पर उन गणना कर रहे हैं:

 method round single base 
----------- ------ ------ ----- 
     date 21324 19891 18458 
     int 23031 21453 19875 
    datediff 23782 23218 22654 
     float 36891 29312 21733 
varchar-112 102984 64016 25048 
varchar-101 123375 65609 7843 
  • दौर एक राउंड ट्रिप वापस datetime करने के लिए CPU समय है।

  • एकल वैकल्पिक डेटा प्रकार के लिए एक रूपांतरण के लिए सीपीयू समय है (जिसने समय हिस्से को हटाने का दुष्प्रभाव है)। single - (round - single):

  • आधारsingle दो आमंत्रण के बीच अंतर से घटाकर की गणना है। यह एक बॉलपार्क आंकड़ा है जो उस डेटा प्रकार से रूपांतरण को मानता है और datetime लगभग किसी भी दिशा में समान होता है। ऐसा प्रतीत होता है कि यह धारणा सही नहीं है लेकिन करीब है क्योंकि मान केवल 200 अप   एमएस के करीब हैं, केवल एक अपवाद के साथ।

एक और दिलचस्प बात यह है कि आधार लागत एकल Convert(date) विधि (जो लगभग 0 लागत हो गया है करने के लिए लगभग बराबर है, के रूप में सर्वर पूर्णांक दिन भाग सही पहले चार बाइट्स से बाहर आंतरिक रूप से निकाल सकते हैं है datetime डेटा प्रकार का)।

निष्कर्ष

तो क्या यह की तरह लग रहा है कि एकल दिशा varchar रूपांतरण विधि के बारे में 1.8   μs लेता है और एकल दिशा DateDiff विधि के बारे में 0.18   μs लेता है। मैं इसे 18458   एमएस के कुल परीक्षण में 25, 9 20,000 पंक्तियों के लिए सबसे रूढ़िवादी "बेस सीपीयू" समय पर आधारित कर रहा हूं, इसलिए 23218   एमएस/25920000 = 0.18   μs। स्पष्ट 10x सुधार बहुत कुछ लगता है, लेकिन जब तक आप सैकड़ों हजारों पंक्तियों (617k पंक्तियों = 1 दूसरी बचत) से निपट रहे हैं, तब तक यह काफी छोटा है।

मेरी राय में, इस छोटे पूर्ण सुधार को भी देखते हुए, DateAdd विधि जीत जाती है क्योंकि यह प्रदर्शन और स्पष्टता का सबसे अच्छा संयोजन है। जिस जवाब के लिए 0.50000004 का "जादू संख्या" आवश्यक है, किसी दिन किसी दिन (पांच शून्य या छः ???) काटने जा रहा है, साथ ही इसे समझना मुश्किल है।

अतिरिक्त नोट्स

जब मैं कुछ समय मैं '12:00:00.003' को 0.50000004 बदल सकते हैं और देखें कि यह कैसे करता जा रहा हूँ मिलता है। इसे उसी datetime मान में परिवर्तित किया गया है और मुझे याद रखना बहुत आसान लगता है।

रुचि रखने वालों के लिए, ऊपर परीक्षण एक सर्वर जहां @@ संस्करण रिटर्न निम्नलिखित पर चलने गया:

माइक्रोसॉफ्ट एसक्यूएल सर्वर 2008 (RTM) - 10.0.1600.22 (इंटेल X86) Jul 9 2008 14: 43:34 कॉपीराइट (c) 1988-2008 माइक्रोसॉफ्ट कार्पोरेशन मानक संस्करण Windows NT 5.2 पर (बिल्ड 3790: सर्विस पैक 2)

+0

+1 SQL सर्वर का कौन सा संस्करण आपने इस तरह से परीक्षण किया था? –

+0

ऐसा लगता है कि आपके टेबल में * सिंगल * और * राउंड * पीछे है। साथ ही, क्या आप समय में कोई अंतर रखते हैं यदि आप 'वर्कर' के बजाय 'char' का उपयोग करते हैं? – Gabe

+0

@Gabe धन्यवाद, तय। चार वर्चर के समान बिल्कुल प्रतीत होता है। – ErikE

11

आपका CAST - FLOOR - CAST पहले से ही, इष्टतम रास्ता कम से कम एमएस SQL ​​सर्वर पर लगता है 2005

कुछ अन्य समाधान मैंने देखा है एक स्ट्रिंग-रूपांतरण है, उन में Select Convert(varchar(11), getdate(),101) की तरह, जो 10

+2

यह इष्टतम तरीका काफी द्वारा नहीं है

select DATEADD(DAY, DATEDIFF(DAY, 0, datetimefield), 0) 

से, एक सा। कृपया [मेरा उत्तर] देखें (http://stackoverflow.com/questions/2775/whats-the-best-way-to-remove-the-time-portion-of-a-datetime-value-sql-server/3696991 # 36 9 6 9 1 9) इसी पृष्ठ पर। – ErikE

+0

हम अपने उत्पादों में से एक में माइकल स्टम द्वारा सुझाई गई विधि का उपयोग करते हैं और यह एक आकर्षण की तरह काम करता है। –

27

एसक्यूएल सर्वर 2008 है एक नया date data type का एक पहलू से धीमी है और इस के लिए इस समस्या को सरल:

SELECT CAST(CAST(GETDATE() AS date) AS datetime) 
16

DATETIME Calculations, Part 1 (एसक्यूएल सर्वर पत्रिका, फरवरी 2007) में इट्ज़िक बेन-गण इस तरह के रूपांतरण करने के तीन तरीकों को दिखाता है (सबसे तेज के लिए सबसे धीमा; दूसरे और तीसरे विधि के बीच अंतर छोटा है):

SELECT CAST(CONVERT(char(8), GETDATE(), 112) AS datetime) 

SELECT DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0) 

SELECT CAST(CAST(GETDATE() - 0.50000004 AS int) AS datetime) 

आपका तकनीक (नाव) के लिए कास्टिंग पत्रिका के अप्रैल अंक में एक पाठक ने सुझाव दिया है। उनके अनुसार, यह प्रदर्शन ऊपर की दूसरी तकनीक की तुलना में प्रदर्शन है।

+0

मेरी राय में फ्लोट करने के लिए कास्टिंग सबसे अच्छा नहीं है। कृपया [मेरा जवाब देखें] (http://stackoverflow.com/questions/2775/whats-the-best-way-to-remove-the-time-portion-of-a-datetime-value-sql-server/3696991 # 36 9 6 9 1 9 0) – ErikE

+0

@Emtucifor मैं मानता हूं कि * 0.50000004 * मूल्य की वजह से तीसरी विधि बहुत अस्पष्ट है, लेकिन ** यह सबसे तेज़ है और आपके परीक्षण पुष्टि करते हैं कि **। इस प्रकार, यह * जितनी जल्दी हो सके * संतुष्ट करता है। –

+0

@Emtucifor इसके अलावा, यहां लिखा गया लेख * 0.50000004 * मान के बारे में बताता है: * हालांकि यह अभिव्यक्ति छोटा है (और कुशल है, जैसा कि मैं जल्द ही प्रदर्शित करूंगा), ** मुझे यह कहना है कि मैं इसके साथ असहज महसूस करता हूं * *। मुझे यकीन नहीं है कि मैं अपनी अंगुली को बिल्कुल क्यों डाल सकता हूं-शायद क्योंकि यह बहुत तकनीकी है, और आप इसमें डेटाटाइम से संबंधित तर्क नहीं देख सकते हैं। * –

3

प्रयास करें:

SELECT CONVERT(VARCHAR(10),[YOUR COLUMN NAME],105) [YOURTABLENAME] 
0

SQL2005: मैं dateadd की बजाय कास्ट की सलाह देते हैं।उदाहरण के लिए,

select cast(DATEDIFF(DAY, 0, datetimefield) as datetime) 

मेरी डेटासेट पर लगभग 10% तेजी औसतन (और smalldatetime में कास्टिंग तेजी से अभी भी था)

संबंधित मुद्दे