उत्तर अनुभाग
विभिन्न टी-एसक्यूएल निर्माणों का उपयोग करके इसे फिर से लिखने के विभिन्न तरीके हैं। हम पेशेवरों और विपक्षों को देखेंगे और नीचे एक समग्र तुलना करेंगे।
पहला ऊपर : उपयोग करनाOR
SELECT COUNT(*)
FROM dbo.Users AS u
WHERE u.Age < 18
OR u.Age IS NULL;
उपयोग करने OR
से हमें एक अधिक कुशल सीक प्लान प्राप्त होता है, जो सटीक पंक्तियों को पढ़ता है, जिनकी हमें आवश्यकता होती है, हालांकि यह जोड़ता है कि तकनीकी दुनिया a whole mess of malarkey
क्वेरी प्लान को क्या कहती है।
यह भी ध्यान दें कि सीक को दो बार यहां निष्पादित किया गया है, जो वास्तव में ग्राफिकल ऑपरेटर से अधिक स्पष्ट होना चाहिए:
Table 'Users'. Scan count 2, logical reads 8233, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SQL Server Execution Times:
CPU time = 469 ms, elapsed time = 473 ms.
दूसरा अप : UNION ALL
हमारी क्वेरी के साथ व्युत्पन्न तालिकाओं का उपयोग भी इस तरह से फिर से लिखा जा सकता है
SELECT SUM(Records)
FROM
(
SELECT COUNT(Id)
FROM dbo.Users AS u
WHERE u.Age < 18
UNION ALL
SELECT COUNT(Id)
FROM dbo.Users AS u
WHERE u.Age IS NULL
) x (Records);
यह उसी प्रकार की योजना तैयार करता है, जिसमें कम मल्करी होती है, और ईमानदारी की अधिक स्पष्ट डिग्री के बारे में कि कितनी बार सूचकांक खोजा गया (मांगी?)।
यह OR
क्वेरी के रूप में रीड्स (8233) की समान मात्रा करता है , लेकिन लगभग 100ms सीपीयू समय को बंद कर देता है।
CPU time = 313 ms, elapsed time = 315 ms.
हालांकि, आपको यहां वास्तव में सावधान रहना होगा, क्योंकि यदि यह योजना समानांतर चलने का प्रयास करती है, तो दो अलग-अलग COUNT
संचालन क्रमबद्ध होंगे, क्योंकि वे प्रत्येक एक वैश्विक स्केलर एग्रीगेट माने जाते हैं। यदि हम ट्रेस फ्लैग 8649 का उपयोग करते हुए समानांतर योजना बनाते हैं, तो समस्या स्पष्ट हो जाती है।
SELECT SUM(Records)
FROM
(
SELECT COUNT(Id)
FROM dbo.Users AS u
WHERE u.Age < 18
UNION ALL
SELECT COUNT(Id)
FROM dbo.Users AS u
WHERE u.Age IS NULL
) x (Records)
OPTION(QUERYTRACEON 8649);
हमारी क्वेरी को थोड़ा बदलकर इससे बचा जा सकता है।
SELECT SUM(Records)
FROM
(
SELECT 1
FROM dbo.Users AS u
WHERE u.Age < 18
UNION ALL
SELECT 1
FROM dbo.Users AS u
WHERE u.Age IS NULL
) x (Records)
OPTION(QUERYTRACEON 8649);
अब जब तक हम कॉन्टेक्ट ऑपरेटर से नहीं टकराते हैं, तब तक सीक पर प्रदर्शन करने वाले दोनों नोड्स पूरी तरह से समानांतर हो जाते हैं।
इसके लायक क्या है, पूरी तरह से समानांतर संस्करण में कुछ अच्छा लाभ है। लगभग 100 और रीड की लागत पर, और लगभग 90ms अतिरिक्त CPU समय के साथ, बीता हुआ समय 93ms तक सिकुड़ जाता है।
Table 'Users'. Scan count 12, logical reads 8317, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SQL Server Execution Times:
CPU time = 500 ms, elapsed time = 93 ms.
CROSS APPLY के बारे में क्या?
जादू के बिना कोई जवाब पूरा नहीं होता है CROSS APPLY
!
दुर्भाग्य से, हम और अधिक समस्याओं में भाग लेते हैं COUNT
।
SELECT SUM(Records)
FROM dbo.Users AS u
CROSS APPLY
(
SELECT COUNT(Id)
FROM dbo.Users AS u2
WHERE u2.Id = u.Id
AND u2.Age < 18
UNION ALL
SELECT COUNT(Id)
FROM dbo.Users AS u2
WHERE u2.Id = u.Id
AND u2.Age IS NULL
) x (Records);
यह योजना भयानक है। जब आप सेंट पैट्रिक दिवस पर अंतिम शो करते हैं, तो इस तरह की योजना आपके द्वारा समाप्त होती है। हालांकि अच्छी तरह से समानांतर, किसी कारण से यह पीके / सीएक्स को स्कैन कर रहा है। Ew। योजना में 2198 क्वेरी रुपये की लागत है।
Table 'Users'. Scan count 7, logical reads 31676233, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SQL Server Execution Times:
CPU time = 29532 ms, elapsed time = 5828 ms.
यह एक अजीब पसंद है, क्योंकि अगर हम इसे गैर-अनुक्रमित सूचकांक का उपयोग करने के लिए मजबूर करते हैं, तो लागत 1798 क्वेरी रुपये में काफी कम हो जाती है।
SELECT SUM(Records)
FROM dbo.Users AS u
CROSS APPLY
(
SELECT COUNT(Id)
FROM dbo.Users AS u2 WITH (INDEX(ix_Id_Age))
WHERE u2.Id = u.Id
AND u2.Age < 18
UNION ALL
SELECT COUNT(Id)
FROM dbo.Users AS u2 WITH (INDEX(ix_Id_Age))
WHERE u2.Id = u.Id
AND u2.Age IS NULL
) x (Records);
अरे, तलाश करता है! आप वहां देखें। यह भी ध्यान दें कि, के जादू के साथ CROSS APPLY
, हम एक पूरी तरह से समानांतर योजना के लिए नासमझ कुछ भी करने की जरूरत नहीं है।
Table 'Users'. Scan count 5277838, logical reads 31685303, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SQL Server Execution Times:
CPU time = 27625 ms, elapsed time = 4909 ms.
क्रॉस एप्लाइंसेस का अंत COUNT
सामान के बिना बेहतर तरीके से होता है।
SELECT SUM(Records)
FROM dbo.Users AS u
CROSS APPLY
(
SELECT 1
FROM dbo.Users AS u2
WHERE u2.Id = u.Id
AND u2.Age < 18
UNION ALL
SELECT 1
FROM dbo.Users AS u2
WHERE u2.Id = u.Id
AND u2.Age IS NULL
) x (Records);
योजना अच्छी लग रही है, लेकिन रीड और सीपीयू एक सुधार नहीं हैं।
Table 'Users'. Scan count 20, logical reads 17564, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Workfile'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SQL Server Execution Times:
CPU time = 4844 ms, elapsed time = 863 ms.
क्रॉस को फिर से लागू करना एक व्युत्पन्न सम्मिलित परिणाम होने के लिए सटीक एक ही सब कुछ है। मैं क्वेरी प्लान और आँकड़े जानकारी को फिर से पोस्ट नहीं करने जा रहा हूँ - वे वास्तव में नहीं बदले।
SELECT COUNT(u.Id)
FROM dbo.Users AS u
JOIN
(
SELECT u.Id
FROM dbo.Users AS u
WHERE u.Age < 18
UNION ALL
SELECT u.Id
FROM dbo.Users AS u
WHERE u.Age IS NULL
) x ON x.Id = u.Id;
संबंधपरक बीजगणित : पूरी तरह से होने के लिए, और जो सेल्को को मेरे सपने देखने से रोकने के लिए, हमें कम से कम कुछ अजीब तर्कसंगत सामान की कोशिश करने की आवश्यकता है। यहाँ कुछ नहीं है!
के साथ एक प्रयास INTERSECT
SELECT COUNT(*)
FROM dbo.Users AS u
WHERE NOT EXISTS ( SELECT u.Age WHERE u.Age >= 18
INTERSECT
SELECT u.Age WHERE u.Age IS NOT NULL );
Table 'Users'. Scan count 1, logical reads 9157, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SQL Server Execution Times:
CPU time = 1094 ms, elapsed time = 1090 ms.
और यहाँ के साथ एक प्रयास है EXCEPT
SELECT COUNT(*)
FROM dbo.Users AS u
WHERE NOT EXISTS ( SELECT u.Age WHERE u.Age >= 18
EXCEPT
SELECT u.Age WHERE u.Age IS NULL);
Table 'Users'. Scan count 7, logical reads 9247, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SQL Server Execution Times:
CPU time = 2126 ms, elapsed time = 376 ms.
इनको लिखने के और भी तरीके हो सकते हैं, लेकिन मैं उन लोगों को छोड़ दूंगा जो शायद इस्तेमाल करते हैं EXCEPT
और जो INTERSECT
मैं करते हैं, उससे कहीं ज्यादा।
यदि आपको वास्तवCOUNT
में थोड़े थोड़े समय के लिए मेरे प्रश्नों में मेरे द्वारा
उपयोग की जाने वाली गिनती की आवश्यकता है (पढ़ें: मैं कभी-कभी अधिक सम्मिलित परिदृश्यों के साथ आने के लिए बहुत आलसी हूं)। यदि आपको केवल एक गिनती की आवश्यकता है, तो आप एक CASE
ही चीज़ के बारे में करने के लिए एक अभिव्यक्ति का उपयोग कर सकते हैं ।
SELECT SUM(CASE WHEN u.Age < 18 THEN 1
WHEN u.Age IS NULL THEN 1
ELSE 0 END)
FROM dbo.Users AS u
SELECT SUM(CASE WHEN u.Age < 18 OR u.Age IS NULL THEN 1
ELSE 0 END)
FROM dbo.Users AS u
इन दोनों को एक ही योजना मिलती है और एक ही सीपीयू और पढ़ने की विशेषताएँ होती हैं।
Table 'Users'. Scan count 1, logical reads 9157, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
SQL Server Execution Times:
CPU time = 719 ms, elapsed time = 719 ms.
विजेता?
मेरे परीक्षणों में, एक व्युत्पन्न तालिका पर SUM के साथ मजबूर समानांतर योजना ने सबसे अच्छा प्रदर्शन किया। और हाँ, इन प्रश्नों में से कई की मदद की जा सकती है ताकि दोनों विधेयकों के लिए कुछ फ़िल्टर किए गए अनुक्रमितों को जोड़ा जा सके, लेकिन मैं दूसरों के लिए कुछ प्रयोग छोड़ना चाहता था।
SELECT SUM(Records)
FROM
(
SELECT 1
FROM dbo.Users AS u
WHERE u.Age < 18
UNION ALL
SELECT 1
FROM dbo.Users AS u
WHERE u.Age IS NULL
) x (Records)
OPTION(QUERYTRACEON 8649);
धन्यवाद!
NOT EXISTS ( INTERSECT / EXCEPT )
प्रश्नों के बिना काम कर सकते हैंINTERSECT / EXCEPT
भागों:WHERE NOT EXISTS ( SELECT u.Age WHERE u.Age >= 18 );
एक और तरीका है - का उपयोग करता हैEXCEPT
:SELECT COUNT(*) FROM (SELECT UserID FROM dbo.Users EXCEPT SELECT UserID FROM dbo.Users WHERE u.Age >= 18) AS u ;
(जहां UserID पी या किसी अद्वितीय नहीं अशक्त स्तंभ (रों) है)।