SQL Server 2008 और बाद के संस्करण
SQL सर्वर 2008 और बाद में, निश्चित रूप से सबसे तेज़ तरीका है Convert(date, @date)
. इसे एक datetime
पर वापस डाला जा सकता है या datetime2
यदि आवश्यक हो।
SQL Server 2005 और पुराने में वास्तव में सबसे अच्छा क्या है?
मैंने SQL सर्वर में किसी दिनांक से समय को कम करने के लिए सबसे तेज़ क्या है, इसके बारे में असंगत दावे देखे हैं, और कुछ लोगों ने यह भी कहा कि उन्होंने परीक्षण किया, लेकिन मेरा अनुभव अलग रहा है। तो चलिए कुछ और कड़े परीक्षण करते हैं और सभी के पास स्क्रिप्ट है ताकि अगर मैं कोई गलती करता हूं तो लोग मुझे सुधार सकते हैं।
फ्लोट रूपांतरण सटीक नहीं हैं
सबसे पहले, मैं datetime
. को कनवर्ट करने से दूर रहूंगा करने के लिए float
, क्योंकि यह सही ढंग से परिवर्तित नहीं होता है। आप समय निकालने वाली चीज़ को सही ढंग से करने से दूर हो सकते हैं, लेकिन मुझे लगता है कि इसका उपयोग करना एक बुरा विचार है क्योंकि यह डेवलपर्स को स्पष्ट रूप से बताता है कि यह एक सुरक्षित संचालन है और यह नहीं है . एक नज़र डालें:
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
में कनवर्ट करने की कोई आवश्यकता नहीं है . तो आप इससे बचकर कुछ सीपीयू बचा सकते हैं, जब तक कि आपको प्रदर्शन उद्देश्यों के लिए अंतिम मूल्य की आवश्यकता न हो। आप अपरिवर्तित मान के अनुसार GROUP भी कर सकते हैं और रूपांतरण को केवल 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
रूपांतरण लगभग दोगुना? यह सीपीयू के उस हिस्से को प्रकट करता है जो प्रश्नों में तिथि गणना के लिए समर्पित है। CPU उपयोग के कुछ हिस्से ऐसे हैं जिनमें दिनांक गणना शामिल नहीं है, और यह उपरोक्त प्रश्नों में 198775 ms के करीब प्रतीत होता है। फिर रूपांतरण में कुछ अतिरिक्त राशि लगती है, इसलिए यदि दो रूपांतरण हैं, तो उस राशि का लगभग दो बार उपयोग किया जाता है।
अधिक जांच से पता चलता है कि Convert(, 112)
. की तुलना में , Convert(, 101)
query में कुछ अतिरिक्त CPU खर्च होता है (क्योंकि यह एक लंबे varchar
. का उपयोग करता है ?), क्योंकि दूसरा रूपांतरण date
. पर वापस आ गया है varchar
. में प्रारंभिक रूपांतरण जितना खर्च नहीं होता है , लेकिन Convert(, 112)
. के साथ यह समान 20000 ms CPU आधार लागत के करीब है।
यहाँ 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 समय है । -
एकल वैकल्पिक डेटा प्रकार में एकल रूपांतरण के लिए CPU समय है (जिसका समय भाग को हटाने का दुष्प्रभाव है)।
-
आधार
single
. से घटाने की गणना है दो आह्वानों के बीच का अंतर:single - (round - single)
. यह एक बॉलपार्क आंकड़ा है जो उस डेटा प्रकार औरdatetime
. में और उससे रूपांतरण मानता है दोनों दिशाओं में लगभग समान है। ऐसा लगता है कि यह धारणा सही नहीं है, लेकिन करीब है क्योंकि सभी मान केवल एक अपवाद के साथ 20000 एमएस के करीब हैं।
एक और दिलचस्प बात यह है कि मूल लागत लगभग एक Convert(date)
. के बराबर है विधि (जिसकी लागत लगभग 0 होनी चाहिए, क्योंकि सर्वर datetime
के पहले चार बाइट्स में से पूर्णांक दिन के हिस्से को आंतरिक रूप से निकाल सकता है। डेटा प्रकार)।
निष्कर्ष
तो ऐसा लगता है कि सिंगल-दिशा varchar
रूपांतरण विधि में लगभग 1.8 μs और एकल-दिशा DateDiff
का समय लगता है विधि लगभग 0.18 μs लेती है। मैं इसे 25,920,000 पंक्तियों के लिए 18458 एमएस के अपने परीक्षण में सबसे रूढ़िवादी "बेस सीपीयू" समय पर आधारित कर रहा हूं, इसलिए 23218 एमएस / 25920000 =0.18 μs। स्पष्ट रूप से 10x सुधार बहुत कुछ लगता है, लेकिन यह स्पष्ट रूप से बहुत छोटा है जब तक कि आप सैकड़ों हजारों पंक्तियों (617k पंक्तियों =1 सेकंड की बचत) के साथ काम नहीं कर रहे हैं।
यहां तक कि इस छोटे से पूर्ण सुधार को देखते हुए, मेरी राय में, DateAdd
विधि जीतती है क्योंकि यह प्रदर्शन और स्पष्टता का सबसे अच्छा संयोजन है। उत्तर जिसके लिए 0.50000004
. के "मैजिक नंबर" की आवश्यकता है किसी दिन किसी को काटने वाला है (पांच शून्य या छह???), साथ ही इसे समझना कठिन है।
अतिरिक्त नोट
जब मुझे कुछ समय मिलेगा तो मैं 0.50000004
को बदलने जा रहा हूँ करने के लिए '12:00:00.003'
और देखें कि यह कैसे करता है। इसे उसी datetime
. में बदल दिया जाता है मूल्य और मुझे याद रखना बहुत आसान लगता है।
रुचि रखने वालों के लिए, उपरोक्त परीक्षण एक सर्वर पर चलाए गए थे जहां @@ संस्करण निम्नलिखित लौटाता है:
<ब्लॉकक्वॉट>Microsoft SQL Server 2008 (RTM) - 10.0.1600.22 (Intel X86) जुलाई 9 2008 14:43:34 कॉपीराइट (c) 1988-2008 Microsoft Corporation मानक संस्करण Windows NT 5.2 पर (बिल्ड 3790:सर्विस पैक 2)