वापस जब SQL Server 2012 अभी भी बीटा में था, मैंने नए FORMAT()
. के बारे में ब्लॉग किया था फ़ंक्शन:SQL सर्वर v.Next (Denali):CTP3 T-SQL एन्हांसमेंट:FORMAT ()।
उस समय, मैं नई कार्यक्षमता को लेकर इतना उत्साहित था, कि मैंने कोई प्रदर्शन परीक्षण करने के बारे में सोचा भी नहीं था। मैंने इसे एक और हालिया ब्लॉग पोस्ट में संबोधित किया था, लेकिन पूरी तरह से डेटाटाइम से स्ट्रिपिंग टाइम के संदर्भ में:डेटाटाइम से ट्रिमिंग टाइम - एक फॉलो-अप।
पिछले हफ्ते, मेरे अच्छे दोस्त जेसन हॉर्नर (ब्लॉग | @jasonhorner) ने मुझे इन ट्वीट्स से ट्रोल किया:
. से |
|
इसके साथ मेरी समस्या बस यह है कि FORMAT()
सुविधाजनक दिखता है, लेकिन यह अन्य दृष्टिकोणों की तुलना में बेहद अक्षम है (ओह और वह AS VARCHAR
बात भी खराब है)। यदि आप इसे ओसी-ट्वोसी कर रहे हैं और छोटे परिणामों के लिए, मैं इसके बारे में ज्यादा चिंता नहीं करता; लेकिन बड़े पैमाने पर, यह काफी महंगा हो सकता है। एक उदाहरण से समझाता हूँ। सबसे पहले, आइए 1000 छद्म यादृच्छिक तिथियों के साथ एक छोटी तालिका बनाएं:
SELECT TOP (1000) d = DATEADD(DAY, CHECKSUM(NEWID())%1000, o.create_date) INTO dbo.dtTest FROM sys.all_objects AS o ORDER BY NEWID(); GO CREATE CLUSTERED INDEX d ON dbo.dtTest(d);
अब, इस तालिका के डेटा के साथ कैश को प्राइम करें, और उन तीन सामान्य तरीकों का वर्णन करें जो लोग केवल समय पर प्रस्तुत करते हैं:
SELECT d, CONVERT(DATE, d), CONVERT(CHAR(10), d, 120), FORMAT(d, 'yyyy-MM-dd') FROM dbo.dtTest;
अब, इन विभिन्न तकनीकों का उपयोग करने वाली अलग-अलग क्वेरी करते हैं। हम उन्हें हर 5 बार चलाएंगे और हम निम्नलिखित विविधताएं चलाएंगे:
- सभी 1,000 पंक्तियों का चयन करना
- क्लस्टर इंडेक्स की के अनुसार टॉप (1) का चयन करना
- एक वैरिएबल को असाइन करना (जो एक पूर्ण स्कैन के लिए बाध्य करता है, लेकिन SSMS रेंडरिंग को प्रदर्शन में हस्तक्षेप करने से रोकता है)
यहाँ स्क्रिप्ट है:
-- select all 1,000 rows GO SELECT d FROM dbo.dtTest; GO 5 SELECT d = CONVERT(DATE, d) FROM dbo.dtTest; GO 5 SELECT d = CONVERT(CHAR(10), d, 120) FROM dbo.dtTest; GO 5 SELECT d = FORMAT(d, 'yyyy-MM-dd') FROM dbo.dtTest; GO 5 -- select top 1 GO SELECT TOP (1) d FROM dbo.dtTest ORDER BY d; GO 5 SELECT TOP (1) CONVERT(DATE, d) FROM dbo.dtTest ORDER BY d; GO 5 SELECT TOP (1) CONVERT(CHAR(10), d, 120) FROM dbo.dtTest ORDER BY d; GO 5 SELECT TOP (1) FORMAT(d, 'yyyy-MM-dd') FROM dbo.dtTest ORDER BY d; GO 5 -- force scan but leave SSMS mostly out of it GO DECLARE @d DATE; SELECT @d = d FROM dbo.dtTest; GO 5 DECLARE @d DATE; SELECT @d = CONVERT(DATE, d) FROM dbo.dtTest; GO 5 DECLARE @d CHAR(10); SELECT @d = CONVERT(CHAR(10), d, 120) FROM dbo.dtTest; GO 5 DECLARE @d CHAR(10); SELECT @d = FORMAT(d, 'yyyy-MM-dd') FROM dbo.dtTest; GO 5
अब, हम निम्न क्वेरी के साथ प्रदर्शन को माप सकते हैं (मेरा सिस्टम बहुत शांत है; आपके लिए, आपको केवल execution_count
की तुलना में अधिक उन्नत फ़िल्टरिंग करने की आवश्यकता हो सकती है ):
SELECT [t] = CONVERT(CHAR(255), t.[text]), s.total_elapsed_time, avg_elapsed_time = CONVERT(DECIMAL(12,2),s.total_elapsed_time / 5.0), s.total_worker_time, avg_worker_time = CONVERT(DECIMAL(12,2),s.total_worker_time / 5.0), s.total_clr_time FROM sys.dm_exec_query_stats AS s CROSS APPLY sys.dm_exec_sql_text(s.[sql_handle]) AS t WHERE s.execution_count = 5 AND t.[text] LIKE N'%dbo.dtTest%' ORDER BY s.last_execution_time;
मेरे मामले में परिणाम काफी सुसंगत थे:
क्वेरी (छोटा गया) | <वें colspan=3>अवधि (माइक्रोसेकंड)||||
---|---|---|---|---|
कुल_बीता हुआ | औसत_बीता हुआ | total_clr | ||
1,000 पंक्तियां चुनें | SELECT d FROM dbo.dtTest ORDER BY d; |
1,170 |
234.00 |
0 |
SELECT d = CONVERT(DATE, d) FROM dbo.dtTest ORDER BY d; |
2,437 |
487.40 |
0 |
|
SELECT d = CONVERT(CHAR(10), d, 120) FROM dbo.dtTest ORD ... |
151,521 |
30,304.20 |
0 |
|
SELECT d = FORMAT(d, 'yyyy-MM-dd') FROM dbo.dtTest ORDER ... |
240,152 |
48,030.40 |
107,258 |
|
SELECT TOP (1) | SELECT TOP (1) d FROM dbo.dtTest ORDER BY d; |
251 |
50.20 |
0 |
SELECT TOP (1) CONVERT(DATE, d) FROM dbo.dtTest ORDER BY ... |
440 |
88.00 |
0 |
|
SELECT TOP (1) CONVERT(CHAR(10), d, 120) FROM dbo.dtTest ... |
301 |
60.20 |
0 |
|
SELECT TOP (1) FORMAT(d, 'yyyy-MM-dd') FROM dbo.dtTest O ... |
1,094 |
218.80 |
589 |
|
Assign variable | DECLARE @d DATE; SELECT @d = d FROM dbo.dtTest; |
639 |
127.80 |
0 |
DECLARE @d DATE; SELECT @d = CONVERT(DATE, d) FROM dbo.d ... |
644 |
128.80 |
0 |
|
DECLARE @d CHAR(10); SELECT @d = CONVERT(CHAR(10), d, 12 ... | 1,972 |
394.40 |
0 |
|
DECLARE @d CHAR(10); SELECT @d = FORMAT(d, 'yyyy-MM-dd') ... |
118,062 |
23,612.40 |
98,556 |
And to visualize the avg_elapsed_time
. की कल्पना करने के लिए आउटपुट (विस्तार करने के लिए क्लिक करें):
FORMAT() स्पष्ट रूप से हारने वाला है:avg_elapsed_time परिणाम (माइक्रोसेकंड)
इन परिणामों से हम क्या सीख सकते हैं (फिर से):
- सबसे पहले और सबसे महत्वपूर्ण,
FORMAT()
महंगा है । FORMAT()
स्वीकार्य रूप से, अधिक लचीलापन प्रदान कर सकते हैं और अधिक सहज ज्ञान युक्त तरीके दे सकते हैं जो सी # जैसी अन्य भाषाओं के अनुरूप हैं। हालाँकि, इसके ओवरहेड के अलावा, और जबकिCONVERT()
स्टाइल नंबर गुप्त और कम विस्तृत हैं, आपको वैसे भी पुराने दृष्टिकोण का उपयोग करना पड़ सकता है, क्योंकिFORMAT()
केवल SQL Server 2012 और नए में मान्य है।- यहां तक कि स्टैंडबाय
CONVERT()
विधि काफी महंगी हो सकती है (हालांकि केवल गंभीर रूप से उस मामले में जहां एसएसएमएस को परिणाम प्रस्तुत करना था - यह स्पष्ट रूप से दिनांक मानों की तुलना में स्ट्रिंग को अलग तरीके से संभालता है)। - डेटाटाइम मान को सीधे डेटाबेस से बाहर निकालना हमेशा सबसे कुशल था। आपको प्रस्तुतिकरण स्तर पर वांछित तिथि को प्रारूपित करने के लिए आपके आवेदन के लिए अतिरिक्त समय लेना चाहिए - यह अत्यधिक संभावना है कि आप एसक्यूएल सर्वर को सुंदर प्रारूप में शामिल नहीं करना चाहते हैं (और वास्तव में कई तर्क देंगे कि यह वह जगह है जहां वह तर्क हमेशा संबंधित होता है)।
हम यहां केवल माइक्रोसेकंड की बात कर रहे हैं, लेकिन हम भी केवल 1,000 पंक्तियों की बात कर रहे हैं। इसे अपने वास्तविक तालिका आकारों तक बढ़ाएं, और गलत स्वरूपण दृष्टिकोण चुनने का प्रभाव विनाशकारी हो सकता है।
यदि आप इस प्रयोग को अपनी मशीन पर आज़माना चाहते हैं, तो मैंने एक नमूना स्क्रिप्ट अपलोड की है:FormatIsNiceAndAllbut.sql_.zip