कार्ल ने पहली बार SQL सर्वर CTE के बारे में सुना जब वह अपने SQL कोड को आंखों के लिए आसान बनाने के लिए कुछ ढूंढ रहा था। जब आप इसे देखते हैं तो यह एक तरह का सिरदर्द होता है। उनके संबंधित सहयोगी एंटोन ने उनसे सीटीई के बारे में पूछा। कार्ल को लगा कि एंटन अपने सिरदर्द की बात कर रहा है। हो सकता है कि उसने यह सब गलत सुना हो, इसलिए उसने उत्तर दिया, "बिल्कुल नहीं।" मजेदार बात यह है कि वह क्रॉनिक ट्रॉमेटिक एन्सेफेलोपैथी का जिक्र कर रहे थे, जो एक सीटीई भी है - एक न्यूरोडीजेनेरेटिव बीमारी जो बार-बार सिर में चोट लगने के कारण होती है। लेकिन कार्ल की प्रतिक्रिया के आधार पर, एंटोन निश्चित रूप से जानता था कि उसका सहयोगी उसके बारे में अनजान था जो वह कह रहा था।
सीटीई शुरू करने का क्या ही शानदार तरीका है! तो, इससे पहले कि आप एक ही नाव में चढ़ें, आइए स्पष्ट करें कि SQL दुनिया में SQL CTE या कॉमन टेबल एक्सप्रेशन क्या है?
आप यहां मूल बातें पढ़ सकते हैं। इस बीच, हम इस असामान्य कहानी में जो हुआ उसके बारे में थोड़ा और जानेंगे।
4 SQL सर्वर में CTE के बारे में मूलभूत सामग्री
“एक SQL CTE का एक नाम होता है”
एंटोन ने इस विचार के साथ शुरुआत की कि SQL CTE को अस्थायी रूप से परिणाम सेट नाम दिया गया है। अस्थायी साधन होने के कारण, CTE का दायरा सीमित है।
"तो, यह एक सबक्वायरी की तरह है?" कार्ल ने पूछा।
"एक तरह से, हाँ। लेकिन आप एक उपश्रेणी का नाम नहीं दे सकते," एंटोन ने कहा। "एक सीटीई का नाम एक नाम के साथ एक टेबल जैसा होता है। हालाँकि, बनाने के बजाय, आप इसे बनाने के लिए WITH का उपयोग करते हैं।" फिर, उन्होंने कागज पर वाक्य रचना लिखी:
WITH <cte_name>(<column list>)
AS
(
<inner query defining the CTE>
)
<outer query against CTE>
“चुनने के बाद CTE चला गया”
एंटोन ने एसक्यूएल सीटीई के दायरे को समझाते हुए जारी रखा।
"एक अस्थायी तालिका प्रक्रिया के दायरे में या विश्व स्तर पर मौजूद हो सकती है। लेकिन जब सेलेक्ट किया जाता है तो सीटीई चला जाता है, ”उन्होंने इसे एक तुकबंदी के साथ कहा। "वही बात अगर आप इसे INSERT, UPDATE, या DELETE के लिए उपयोग करते हैं," उन्होंने जारी रखा।
“आप इसका पुन:उपयोग नहीं कर सकते”
"एक दृश्य या एक अस्थायी तालिका के विपरीत, आप SQL CTE का पुन:उपयोग नहीं कर सकते। नाम वहाँ है, इसलिए आप इसे आंतरिक और बाहरी क्वेरी में संदर्भित कर सकते हैं। लेकिन बस इतना ही," एंटोन ने बताया।
"तो, SQL CTE के बारे में क्या बड़ी बात है?" कार्ल ने पूछा।
“आप अपने कोड को अधिक पठनीय बना सकते हैं”
"बड़ी बात?" एंटोन ने सवाल वापस कर दिया। "ऐसा है कि आप अपना कोड आसानी से पठनीय बना सकते हैं। क्या आप यही नहीं खोज रहे हैं?”
"यह सही है," कार्ल ने स्वीकार किया।
तो, कार्ल के लिए अगला तार्किक कदम क्या है?
एसक्यूएल में सीटीई के बारे में अतिरिक्त सामग्री
अगले दिन, कार्ल ने SQL CTE के लिए अपनी खोज जारी रखी। उपरोक्त के अलावा, उसने जो पाया वह है:
- एसक्यूएल सीटीई गैर-पुनरावर्ती या पुनरावर्ती हो सकता है।
- न केवल SQL सर्वर बल्कि MySQL और Oracle भी इस विचार का समर्थन करते हैं। वास्तव में, यह SQL-99 विनिर्देशों का एक भाग है।
- हालांकि इसका उपयोग SQL कोड को सरल बनाने के लिए किया जाता है, यह प्रदर्शन में सुधार नहीं करता है।
- और यह सबक्वेरी और अस्थायी तालिकाओं को भी प्रतिस्थापित नहीं करेगा। प्रत्येक का अपना स्थान और उपयोग होता है।
संक्षेप में, यह किसी प्रश्न को व्यक्त करने का दूसरा तरीका है ।
लेकिन कार्ल अधिक विवरण के लिए भूखा था, इसलिए उसने यह देखना जारी रखा कि क्या काम करेगा, क्या नहीं, और यह बनाम सबक्वेरी और अस्थायी तालिकाओं का प्रदर्शन कैसे करेगा।
SQL सर्वर CTE में क्या काम करेगा?
सीटीई के बारे में और अधिक जानने के लिए, कार्ल ने नीचे सूचीबद्ध किया कि SQL सर्वर क्या स्वीकार करेगा। उनकी पढ़ाई पर भी एक नज़र डालें।
इनलाइन या बाहरी कॉलम उपनाम असाइन करें
SQL CTEs स्तंभ उपनाम निर्दिष्ट करने के दो रूपों का समर्थन करते हैं। पहला इनलाइन फॉर्म है, जैसा कि नीचे दिया गया उदाहरण है:
-- Use an Inline column alias
USE AdventureWorks
GO;
WITH Sales_CTE
AS
(
SELECT SalesPersonID, COUNT(*) AS NumberOfOrders
FROM Sales.SalesOrderHeader
WHERE SalesPersonID IS NOT NULL
GROUP BY SalesPersonID
)
SELECT
a.SalesPersonID
,a.NumberOfOrders
FROM Sales_CTE a
उपरोक्त कोड सीटीई परिभाषा के भीतर कॉलम उपनाम का उपयोग करता है जब इसे सेलेक्ट स्टेटमेंट में असाइन किया जाता है। क्या आपने COUNT(*) AS NumberOfOrders . देखा ? वह इनलाइन फॉर्म है।
अब, एक और उदाहरण बाहरी रूप है:
-- Use an external column alias
USE AdventureWorks
GO;
WITH Sales_CTE(SalesPersonID, NumberOfOrders)
AS
(
SELECT SalesPersonID, COUNT(*)
FROM Sales.SalesOrderHeader
WHERE SalesPersonID IS NOT NULL
GROUP BY SalesPersonID
)
SELECT
a.SalesPersonID
,a.NumberOfOrders
FROM Sales_CTE a
CTE नाम सेट करने के बाद कॉलम को कोष्ठक में भी परिभाषित किया जा सकता है। Sales_CTE के साथ नोटिस (SalesPersonID, NumberOfOrders) ।
SQL में CTE, SELECT, INSERT, UPDATE, या DELETE से पहले आता है
यह अगला आइटम सीटीई के उपभोग के बारे में है। पहला और सामान्य उदाहरण तब होता है जब यह एक सेलेक्ट स्टेटमेंट से पहले होता है।
-- List down all Salespersons with their all-time number of orders
USE AdventureWorks
GO;
WITH Sales_CTE (SalesPersonID, NumberOfOrders)
AS
(
SELECT SalesPersonID, COUNT(*)
FROM Sales.SalesOrderHeader
WHERE SalesPersonID IS NOT NULL
GROUP BY SalesPersonID
)
SELECT
a.SalesPersonID
,CONCAT(P.LastName,', ',P.FirstName,' ',P.MiddleName) AS SalesPerson
,a.NumberOfOrders
FROM Sales_CTE a
INNER JOIN Person.Person p ON a.SalesPersonID = p.BusinessEntityID
यह उदाहरण क्या दिखाता है?
- Sales_CTE - सीटीई का नाम।
- (SalesPersonID, NumberOfOrders) - सीटीई कॉलम की परिभाषा।
- SalesPersonID चुनें, COUNT(*) Sales से.SalesOrderHeader जहां SalesPersonID SalesPersonID द्वारा पूर्ण समूह नहीं है - आंतरिक चयन जो सीटीई को परिभाषित करता है।
- सेल्सपर्सनआईडी, CONCAT(P.LastName,', ',P.FirstName,' ',P.MiddleName) को सेल्सपर्सन के रूप में चुनें - बाहरी क्वेरी जो सीटीई की खपत करती है। यह उदाहरण सीटीई का उपभोग करने के लिए एक चयन का उपयोग करता है।
- Sales_CTE से - सीटीई को बाहरी क्वेरी का संदर्भ।
एक सेलेक्ट के अलावा, यह INSERT, UPDATE और DELETE के साथ भी काम करता है। यहां INSERT का उपयोग करने का एक उदाहरण दिया गया है:
-- add a 10% increase to Employee 16 after 1 year from the previous increase.
USE AdventureWorks
GO;
WITH LatestEmployeePay
AS
(
SELECT TOP 1
eph.BusinessEntityID
,eph.RateChangeDate
,eph.Rate
,eph.PayFrequency
FROM HumanResources.EmployeePayHistory eph
WHERE eph.BusinessEntityID = 16
ORDER BY eph.RateChangeDate DESC
)
INSERT INTO HumanResources.EmployeePayHistory
SELECT
BusinessEntityID
,DATEADD(d,365,RateChangeDate)
,(Rate * 0.1) + Rate
,PayFrequency
,GETDATE()
FROM LatestEmployeePay
उपरोक्त सूची में, सीटीई कर्मचारी 16 के लिए नवीनतम वेतन प्राप्त करता है। सीटीई के परिणाम सेट का उपयोग तब कर्मचारी भुगतान इतिहास में एक नया रिकॉर्ड डालने के लिए किया जाता है। . कार्ल ने अपने निष्कर्षों को सुरुचिपूर्ण ढंग से दर्ज किया। साथ ही, उन्होंने उपयुक्त उदाहरणों का इस्तेमाल किया।
एक प्रश्न में एकाधिक सीटीई परिभाषित करें
ये सही है। कार्ल ने पाया कि 1 क्वेरी में कई सीटीई संभव हैं। यहां एक उदाहरण दिया गया है:
-- Get the present and previous rate of employee 16
USE AdventureWorks
GO;
WITH LatestEmployeePay
AS
(
SELECT TOP 1
eph.BusinessEntityID
,eph.RateChangeDate
,eph.Rate
FROM HumanResources.EmployeePayHistory eph
WHERE eph.BusinessEntityID = 16
ORDER BY eph.RateChangeDate DESC
),
PreviousEmployeePay AS
(
SELECT TOP 1
eph.BusinessEntityID
,eph.RateChangeDate
,eph.Rate
FROM HumanResources.EmployeePayHistory eph
INNER JOIN LatestEmployeePay lep
ON eph.BusinessEntityID = lep.BusinessEntityID
WHERE eph.BusinessEntityID = 16
AND eph.RateChangeDate < lep.RateChangeDate
ORDER BY eph.RateChangeDate DESC
)
SELECT
a.BusinessEntityID
,a.Rate
,a.RateChangeDate
,b.Rate AS PreviousRate
FROM LatestEmployeePay a
INNER JOIN PreviousEmployeePay b
ON a.BusinessEntityID = b.BusinessEntityID
उपरोक्त कोड एक प्रश्न में 2 सीटीई का उपयोग करता है, अर्थात् नवीनतम कर्मचारी भुगतान और पिछला कर्मचारी वेतन ।
एक सीटीई एकाधिक बार देखें
पिछले उदाहरण के लिए और भी बहुत कुछ है। यह भी ध्यान दें कि आप पहले सीटीई से दूसरे सीटीई में शामिल हो सकते हैं। अंत में, बाहरी क्वेरी दोनों 2 सीटीई में शामिल हो सकती है। नवीनतम कर्मचारी वेतन दो बार संदर्भित किया गया है।
एसक्यूएल सीटीई के लिए तर्क पास करें
तर्क, जैसे चर, एक सीटीई के साथ पारित किए जा सकते हैं:
DECLARE @SalesPersonID INT = 275;
WITH Sales_CTE
AS
(
SELECT SalesPersonID, COUNT(*) AS NumberOfOrders
FROM Sales.SalesOrderHeader
WHERE SalesPersonID = @SalesPersonID
GROUP BY SalesPersonID
)
SELECT SalesPersonID, NumberOfOrders
FROM Sales_CTE
उपरोक्त कोड एक वैरिएबल @SalesPersonID . घोषित और सेट करके शुरू होता है . फिर परिणाम को फ़िल्टर करने के लिए मान को CTE को पास कर दिया जाता है।
कर्सर में उपयोग करें
एक SQL कर्सर परिणामों के माध्यम से एक सेलेक्ट स्टेटमेंट और लूप का उपयोग कर सकता है। साथ ही, इसके साथ एक SQL CTE का उपयोग किया जा सकता है:
DECLARE @SalesPersonID INT
DECLARE @NumberofOrders INT
DECLARE sales_cursor CURSOR FOR
WITH Sales_CTE (SalesPersonID, NumberOfOrders)
AS
(
SELECT SalesPersonID, COUNT(*)
FROM Sales.SalesOrderHeader
WHERE SalesPersonID IS NOT NULL
GROUP BY SalesPersonID
)
SELECT salespersonid, numberoforders
FROM Sales_CTE;
OPEN sales_cursor
FETCH NEXT FROM sales_cursor INTO @SalesPersonID, @NumberofOrders
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT 'SalesPersonID: ' + CAST(@SalesPersonID AS VARCHAR)
PRINT '# of Orders: ' + CAST(@NumberofOrders AS VARCHAR)
FETCH NEXT FROM sales_cursor INTO @SalesPersonID, @NumberofOrders
END
CLOSE sales_cursor
DEALLOCATE sales_cursor;
पुनरावर्ती CTE में अस्थायी तालिका का उपयोग करें
रिकर्सिव सीटीई एक एंकर सदस्य और सीटीई परिभाषा के भीतर एक पुनरावर्ती सदस्य का उपयोग करता है। यह एक तालिका के भीतर पदानुक्रम प्राप्त करने में मदद करता है। SQL CTE इस उद्देश्य के लिए एक अस्थायी तालिका का भी उपयोग कर सकता है। नीचे एक उदाहरण देखें:
-- Create a Crew table.
CREATE TABLE #EnterpriseDSeniorOfficers
(
CrewID SMALLINT NOT NULL,
FirstName NVARCHAR(30) NOT NULL,
LastName NVARCHAR(40) NOT NULL,
CrewRank NVARCHAR(50) NOT NULL,
HigherRankID INT NULL,
CONSTRAINT PK_CrewID PRIMARY KEY CLUSTERED (CrewID ASC)
);
-- Populate the table with values.
INSERT INTO #EnterpriseDSeniorOfficers VALUES
(1, N'Jean-Luc', N'Picard', N'Captain',NULL)
,(2, N'William', N'Riker', N'First Officer',1)
,(3, N'Data', N'', N'Second Officer',1)
,(4, N'Worf', N'', N'Chief of Security',1)
,(5, N'Deanna', N'Troi', N'Ship Counselor',1)
,(6, N'Beveryly', N'Crusher', N'Chief Medical Officer',1)
,(7, N'Geordi', N'LaForge', N'Chief Engineer',1);
WITH DirectReports(HigherRankID, CrewID, Title, CrewLevel) AS
(
SELECT HigherRankID, CrewID, CrewRank, 0 as CrewLevel
FROM #EnterpriseDSeniorOfficers
WHERE HigherRankID IS NULL
UNION ALL
SELECT e.HigherRankID, e.CrewID, e.CrewRank, CrewLevel + 1
FROM #EnterpriseDSeniorOfficers AS e
INNER JOIN DirectReports AS d
ON e.HigherRankID = d.CrewID
)
SELECT HigherRankID, CrewID, Title, CrewLevel
FROM DirectReports
OPTION (MAXRECURSION 2)
ORDER BY HigherRankID;
DROP TABLE #EnterpriseDSeniorOfficers
कार्ल ने इस सीटीई को विदारक करके समझाया। यहां बताया गया है कि यह कैसे होता है।
एंकर सदस्य शून्य (0) क्रू लेवल वाला पहला सेलेक्ट स्टेटमेंट होता है:
SELECT HigherRankID, CrewID, CrewRank, 0 as CrewLevel
FROM #EnterpriseDSeniorOfficers
WHERE HigherRankID IS NULL
इस एंकर सदस्य को पदानुक्रम का रूट नोड मिलता है। WHERE क्लॉज निर्दिष्ट करता है कि रूट लेवल (HerRankID IS NULL . है) )।
पुनरावर्ती सदस्य जो चाइल्ड नोड्स प्राप्त करेगा नीचे निकाला गया है:
SELECT e.HigherRankID, e.CrewID, e.CrewRank, CrewLevel + 1
FROM #EnterpriseDSeniorOfficers AS e
INNER JOIN DirectReports AS d
ON e.HigherRankID = d.CrewID
एक विकल्प (MAXRECURSION 2) . भी है बाहरी क्वेरी में उपयोग किया जाता है। जब एक अनंत लूप पुनरावर्ती क्वेरी से परिणामित होता है, तो पुनरावर्ती CTE समस्याग्रस्त हो सकते हैं। MAXRECURSION 2 इस गड़बड़ी से बचता है - यह लूप को केवल 2 रिकर्सन तक सीमित करता है।
यह कार्ल की सूची को समाप्त करता है कि क्या काम करेगा। हालाँकि, जो कुछ भी हम सोचते हैं वह काम नहीं कर सकता है। अगला भाग इन पर कार्ल के निष्कर्षों पर चर्चा करेगा।
SQL CTE में क्या काम नहीं करेगा?
यहां, हमारे पास उन चीजों की एक सूची है जो SQL CTE का उपयोग करते समय एक त्रुटि उत्पन्न करेगी।
SQL CTE से पहले कोई अर्धविराम नहीं
अगर सीटीई के सामने कोई बयान है, तो उस बयान को अर्धविराम से समाप्त किया जाना चाहिए। WITH क्लॉज अन्य उद्देश्यों के लिए काम कर सकता है जैसे टेबल हिंट में, इस प्रकार, अर्धविराम अस्पष्टता से छुटकारा दिलाएगा। नीचे दिया गया कथन त्रुटि उत्पन्न करेगा:
DECLARE @SalesPersonID INT
SET @SalesPersonID = 275
WITH Sales_CTE
AS
(
SELECT SalesPersonID, COUNT(*) AS NumberOfOrders
FROM Sales.SalesOrderHeader
WHERE SalesPersonID = @SalesPersonID
GROUP BY SalesPersonID
)
SELECT SalesPersonID, NumberOfOrders
FROM Sales_CTE
प्रथम-टाइमर जो अर्धविराम के साथ कथनों को समाप्त नहीं करते थे, इस त्रुटि का सामना करते हैं:
अज्ञात कॉलम
"कॉलम उपनाम रखना भूल गए? फिर, आप एक और त्रुटि के लिए तैयार हैं।" कार्ल ने अपने पेपर में यह कहा और एक नमूना कोड भी प्रदान किया जिसे मैं नीचे साझा कर रहा हूं:
DECLARE @SalesPersonID INT
SET @SalesPersonID = 275;
WITH Sales_CTE
AS
(
SELECT SalesPersonID, COUNT(*)
FROM Sales.SalesOrderHeader
WHERE SalesPersonID = @SalesPersonID
GROUP BY SalesPersonID
)
SELECT SalesPersonID, NumberOfOrders
FROM Sales_CTE
फिर, त्रुटि संदेश पर एक नज़र डालें:
डुप्लिकेट कॉलम नाम
ऊपर #2 से संबंधित एक और त्रुटि सीटीई के भीतर समान कॉलम नाम का उपयोग कर रही है। आप सामान्य चयन कथन में इससे दूर हो सकते हैं, लेकिन सीटीई के साथ नहीं। कार्ल का एक और उदाहरण था:
WITH Sales_CTE
AS
(
SELECT SalesPersonID AS col1, COUNT(*) AS col1
FROM Sales.SalesOrderHeader
GROUP BY SalesPersonID
)
SELECT *
FROM Sales_CTE
शीर्ष या ऑफ़सेट-फ़ेच के बिना खंड द्वारा आदेश
जब हम परिणाम सेट को सॉर्ट करने के लिए इसका उपयोग करते हैं तो मानक SQL तालिका अभिव्यक्तियों में ORDER BY की अनुमति नहीं देता है। हालाँकि, यदि TOP या OFFSET-FETCH का उपयोग किया जाता है, तो ORDER BY एक फ़िल्टरिंग सहायता बन जाता है।
ORDER BY का उपयोग करके कार्ल का उदाहरण यहां दिया गया है:
WITH LatestEmployeePay
AS
(
SELECT
eph.BusinessEntityID
,eph.RateChangeDate
,eph.Rate
,eph.PayFrequency
FROM HumanResources.EmployeePayHistory eph
WHERE eph.BusinessEntityID = 16
ORDER BY eph.RateChangeDate DESC
)
INSERT INTO HumanResources.EmployeePayHistory
SELECT
BusinessEntityID
,DATEADD(d,365,RateChangeDate)
,(Rate * 0.1) + Rate
,PayFrequency
,GETDATE()
FROM LatestEmployeePay
ध्यान दें कि यह वही उदाहरण है जो हमारे पास पहले था, लेकिन इस बार, TOP निर्दिष्ट नहीं है। त्रुटि की जाँच करें:
स्तंभों की संख्या स्तंभ सूची परिभाषा के समान नहीं है
कार्ल ने उसी रिकर्सिव सीटीई उदाहरण का इस्तेमाल किया, लेकिन उन्होंने एंकर सदस्य में एक कॉलम निकाला:
WITH DirectReports(HigherRankID, CrewID, Title, CrewLevel) AS
(
SELECT HigherRankID, CrewID
FROM #EnterpriseDSeniorOfficers
WHERE HigherRankID IS NULL
UNION ALL
SELECT e.HigherRankID, e.CrewID, e.CrewRank, CrewLevel + 1
FROM #EnterpriseDSeniorOfficers AS e
INNER JOIN DirectReports AS d
ON e.HigherRankID = d.CrewID
)
SELECT HigherRankID, CrewID, Title, CrewLevel
FROM DirectReports
ORDER BY HigherRankID;
उपरोक्त कोड बाहरी रूप के साथ तीन-स्तंभ सूची का उपयोग करता है, लेकिन एंकर सदस्य के पास केवल 2 कॉलम थे। इसकी अनुमति नहीं है। इस तरह की गलती करने से त्रुटि उत्पन्न होगी:
CTE में अन्य चीजों की अनुमति नहीं है
ऊपर दी गई सूची के अलावा, यहां कार्ल के कुछ और निष्कर्ष दिए गए हैं जो SQL CTE में गलती से उपयोग करने पर त्रुटियों को ट्रिगर करते हैं।
- क्वेरी संकेतों के साथ SELECT INTO, OPTION क्लॉज का उपयोग करना, और FOR BROWSE का उपयोग करना।
- पुनरावर्ती सदस्य कॉलम की तुलना में एंकर सदस्य कॉलम में विभिन्न डेटा और प्रकार।
- एक पुनरावर्ती CTE के पुनरावर्ती सदस्य में निम्नलिखित कीवर्ड्स का होना:
- शीर्ष
- आउटर जॉइन (लेकिन इनर जॉइन की अनुमति है)
- ग्रुप बाय एंड हैविंग
- उपश्रेणियां
- अलग चुनें
- स्केलर एकत्रीकरण का उपयोग करना।
- पुनरावर्ती सदस्य में उपश्रेणियों का उपयोग करना।
- एसक्यूएल सीटीई नेस्टेड होना।
एसक्यूएल सीटीई बनाम अस्थायी टेबल बनाम सबक्वेरी
कभी-कभी, आप सबक्वेरी का उपयोग करके SQL CTE को फिर से लिख सकते हैं। साथ ही, कभी-कभी, आप प्रदर्शन कारणों से अस्थायी तालिकाओं का उपयोग करके SQL CTE को तोड़ सकते हैं। किसी भी अन्य प्रश्न की तरह, आपको यह जानने के लिए वास्तविक निष्पादन योजना और सांख्यिकी IO की जांच करनी होगी कि कौन सा विकल्प लेना है। एसक्यूएल सीटीई आंखों के अनुकूल हो सकता है, लेकिन यदि आप प्रदर्शन दीवार से टकराते हैं, तो दूसरे विकल्प का उपयोग करें . कोई भी विकल्प दूसरे से तेज नहीं है।
आइए कार्ल के पेपर से तीन प्रश्नों की जांच करें जो समान परिणाम लाते हैं। एक SQL CTE का उपयोग करता है, दूसरा एक सबक्वेरी का उपयोग करता है, और तीसरा एक अस्थायी तालिका का उपयोग करता है। सरलता के लिए, कार्ल ने एक छोटे से परिणाम सेट का उपयोग किया।
कोड और परिणामसेट
यह कई SQL CTE का उपयोग करके शुरू हुआ।
WITH LatestEmployeePay
AS
(
SELECT TOP 1
eph.BusinessEntityID
,eph.RateChangeDate
,eph.Rate
FROM HumanResources.EmployeePayHistory eph
WHERE eph.BusinessEntityID = 16
ORDER BY eph.RateChangeDate DESC
),
PreviousEmployeePay AS
(
SELECT TOP 1
eph.BusinessEntityID
,eph.RateChangeDate
,eph.Rate
FROM HumanResources.EmployeePayHistory eph
INNER JOIN LatestEmployeePay lep
ON eph.BusinessEntityID = lep.BusinessEntityID
WHERE eph.BusinessEntityID = 16
AND eph.RateChangeDate < lep.RateChangeDate
ORDER BY eph.RateChangeDate DESC
)
SELECT
a.BusinessEntityID
,a.Rate
,a.RateChangeDate
,b.Rate AS PreviousRate
FROM LatestEmployeePay a
INNER JOIN PreviousEmployeePay b
ON a.BusinessEntityID = b.BusinessEntityID
अगला एक सबक्वेरी है। जैसा कि आप देखते हैं, सीटीई मॉड्यूलर और पठनीय दिखता है, लेकिन नीचे दी गई सबक्वायरी छोटी है:
SELECT TOP 1
eph.BusinessEntityID
,eph.Rate
,eph.RateChangeDate
,(SELECT TOP 1 eph1.Rate FROM HumanResources.EmployeePayHistory eph1
WHERE eph1.BusinessEntityID=16
AND eph1.RateChangeDate < eph.RateChangeDate
ORDER BY eph1.RateChangeDate DESC) AS PreviousRate
FROM HumanResources.EmployeePayHistory eph
WHERE eph.BusinessEntityID = 16
ORDER BY eph.RateChangeDate DESC;
कार्ल ने इसे कोड के छोटे टुकड़ों में विभाजित करने और फिर अस्थायी तालिकाओं का उपयोग करके परिणामों को संयोजित करने का भी प्रयास किया।
SELECT TOP 1
eph.BusinessEntityID
,eph.RateChangeDate
,eph.Rate
INTO #LatestPay
FROM HumanResources.EmployeePayHistory eph
WHERE eph.BusinessEntityID = 16
ORDER BY eph.RateChangeDate DESC
SELECT TOP 1
eph.BusinessEntityID
,eph.RateChangeDate
,eph.Rate
INTO #PreviousPay
FROM HumanResources.EmployeePayHistory eph
INNER JOIN #LatestPay lep
ON eph.BusinessEntityID = lep.BusinessEntityID
WHERE eph.BusinessEntityID = 16
AND eph.RateChangeDate < lep.RateChangeDate
ORDER BY eph.RateChangeDate DESC
SELECT
a.BusinessEntityID
,a.Rate
,a.RateChangeDate
,b.Rate AS PreviousRate
FROM #LatestPay a
INNER JOIN #PreviousPay b
ON a.BusinessEntityID = b.BusinessEntityID
DROP TABLE #LatestPay
DROP TABLE #PreviousPay
कर्मचारी 16 के लिए वर्तमान और पिछले वेतन प्राप्त करने के इन तीन तरीकों के परिणामों पर एक नज़र डालें। वे समान हैं:
द लॉजिकल रीड्स
सबसे अधिक SQL सर्वर संसाधनों का उपभोग क्या करता है? आइए सांख्यिकी IO को देखें। परिणामों को अच्छी तरह से प्रारूपित करने के लिए कार्ल ने सांख्यिकीपार्सर.कॉम का उपयोग किया - हमारे लिए अच्छा है।
चित्रा 7 एक सबक्वेरी का उपयोग करके सीटीई बनाम सीटीई का उपयोग करने के तार्किक पठन को दर्शाता है:
इसके बाद, अस्थायी तालिकाओं का उपयोग करके कोड को छोटे टुकड़ों में तोड़ते समय कुल तार्किक रीड्स देखें:
तो, क्या अधिक संसाधनों की खपत करता है? कार्ल ने उन्हें स्पष्टता के लिए स्थान दिया।
- सबक्वायरी - 4 लॉजिकल रीड्स (विजेता!)।
- एसक्यूएल सीटीई - 6 तार्किक पढ़ता है।
- अस्थायी तालिकाएँ - 8 तार्किक पठन।
इस उदाहरण में, सबसे तेज़ सबक्वेरी होगी।
वास्तविक निष्पादन योजना
आँकड़ों के IO से हमें मिली तार्किक रीडिंग को समझने के लिए, कार्ल ने वास्तविक निष्पादन योजना की भी जाँच की। उन्होंने CTE से शुरुआत की:
हम इस योजना से कुछ बातें देख सकते हैं:
- नवीनतम कर्मचारी वेतन बाहरी क्वेरी में उपयोग किए जाने पर और जब इसे पिछला कर्मचारी भुगतान से जोड़ा जाता है, तो सीटीई का दो बार मूल्यांकन किया गया था। . तो, हम इसके लिए 2 टॉप नोड देखते हैं।
- हम देखते हैं पिछला कर्मचारी वेतन एक बार मूल्यांकन किया गया।
फिर, एक सबक्वेरी के साथ क्वेरी की वास्तविक निष्पादन योजना देखें:
यहाँ कुछ स्पष्ट बातें हैं:
- योजना आसान है।
- यह आसान है क्योंकि नवीनतम वेतन प्राप्त करने के लिए सबक्वेरी का मूल्यांकन केवल एक बार किया जाता है।
- कोई आश्चर्य नहीं कि CTE के साथ क्वेरी के तार्किक रीड की तुलना में लॉजिकल रीड्स कम हैं।
अंत में, यहाँ वास्तविक निष्पादन योजना है जब कार्ल ने अस्थायी तालिकाओं का उपयोग किया था:
चूंकि यह तीन कथनों का एक बैच है, इसलिए हम योजना में तीन आरेख भी देखते हैं। तीनों सरल हैं, लेकिन सामूहिक योजना उपश्रेणी के साथ क्वेरी की योजना जितनी सरल नहीं है।
समय सांख्यिकी
SQL सर्वर समाधान के लिए dbForge Studio का उपयोग करके, आप क्वेरी प्रोफाइलर में समय के आंकड़ों की तुलना कर सकते हैं। उसके लिए, CTRL-कुंजी दबाए रखें और निष्पादन इतिहास में प्रत्येक क्वेरी के परिणाम नामों पर क्लिक करें:
समय के आँकड़े तार्किक पठन और वास्तविक निष्पादन योजना के अनुरूप हैं। सबक्वेरी सबसे तेज (88ms) चली। इसके बाद सीटीई (199ms) है। अंतिम अस्थायी तालिकाओं (536ms) का उपयोग है।
तो, हमने कार्ल से क्या सीखा?
इस विशेष उदाहरण में, हमने देखा कि जब हम सबसे तेज़ विकल्प चाहते हैं तो सबक्वेरी का उपयोग करना बेहतर होता है। हालांकि, यह एक अलग कहानी हो सकती है यदि आवश्यकताओं का सेट ऐसा नहीं है।
यह जानने के लिए कि किस तकनीक का उपयोग करना है, हमेशा सांख्यिकी IO और वास्तविक निष्पादन योजनाओं की जांच करें।
टेकअवे
मुझे आशा है कि आपने सीटीई (कॉमन टेबल एक्सप्रेशंस) क्या है, यह समझने के लिए अपना सिर दीवार से नहीं टकराया। अन्यथा, आपको सीटीई (क्रोनिक ट्रॉमेटिक एन्सेफैलोपैथी) हो सकता है। मज़ाक को छोड़कर, हमने क्या प्रकट किया?
- सामान्य तालिका अभिव्यक्ति अस्थायी रूप से परिणाम सेट नामित हैं। यह व्यवहार और दायरे में एक सबक्वायरी के करीब है लेकिन स्पष्ट और अधिक मॉड्यूलर है। इसका एक नाम भी है।
- एसक्यूएल सीटीई कोड को सरल बनाने के लिए है, न कि आपकी क्वेरी को तेज करने के लिए।
- हमने जो सात चीजें सीखी हैं, वे SQL CTE पर काम करेंगी।
- पांच चीजें एक त्रुटि को ट्रिगर करेंगी।
- हमने एक बार फिर पुष्टि की है कि सांख्यिकी आईओ और वास्तविक निष्पादन योजना हमेशा आपको बेहतर निर्णय देगी। यह सच है यदि आप अस्थायी तालिकाओं का उपयोग करते हुए एक सीटीई की तुलना एक सबक्वेरी और एक बैच से करते हैं।
बहुत मज़ा आया? फिर सोशल मीडिया बटन दबाए जाने की प्रतीक्षा कर रहे हैं। अपना पसंदीदा चुनें और प्यार बांटें!
यह भी पढ़ें
CTE जटिल, शक्तिशाली प्रश्नों को लिखने में कैसे सहायता कर सकता है:एक प्रदर्शन परिप्रेक्ष्य