के साथ टी-एसक्यूएल खराब प्रदर्शन SQL सर्वर में सामान्य तालिका अभिव्यक्तियों के बारे में मेरा एक प्रदर्शन प्रश्न है। हमारी डेवलपर टीम में जब हम अपने प्रश्नों का निर्माण करते हैं तो हम बहुत सी सीटीई का उपयोग करते हैं। मैं वर्तमान में एक प्रश्न पर काम कर रहा हूं जिसमें भयानक प्रदर्शन था। लेकिन मुझे पता चला कि अगर मैंने श्रृंखला के बीच में उस सीटीई तक सभी रिकॉर्ड्स को एक अस्थायी तालिका में डाला और फिर जारी रखा लेकिन उस टेम्पलेट टेबल से चयन करते हुए मैंने प्रदर्शन में काफी सुधार किया। अब मैं समझने में कुछ सहायता प्राप्त करना चाहता हूं कि इस प्रकार का परिवर्तन केवल इस विशिष्ट क्वेरी पर लागू होता है और क्यों आप नीचे देखे गए दो मामलों को प्रदर्शन में इतना अलग करते हैं। या क्या हम संभवतः हमारी टीम में सीटीई का उपयोग कर सकते हैं और क्या हम आम तौर पर इस मामले से सीखकर प्रदर्शन हासिल कर सकते हैं?सीटीई
यहाँ वास्तव में क्या हो रहा है मुझे करने के लिए समझाने की कोशिश करें ...
कोड पूरा हो गया है और आप और शायद 2005 भी एसक्यूएल सर्वर 2008 पर इसे चलाने के लिए सक्षम हो जाएगा। एक भाग पर टिप्पणी की गई है और मेरा विचार यह है कि आप दो मामलों को एक या दूसरे टिप्पणी करके स्विच कर सकते हैं। आप देख सकते हैं कि अपनी ब्लॉक टिप्पणियां कहां रखनी है, मैंने इन स्थानों को --block comment here
और --end block comment here
यह धीमा प्रदर्शन करने वाला मामला है जो असम्बद्ध डिफ़ॉल्ट है। यहाँ आप कर रहे हैं:
--Declare tables to use in example.
CREATE TABLE #Preparation
(
Date DATETIME NOT NULL
,Hour INT NOT NULL
,Sales NUMERIC(9,2)
,Items INT
);
CREATE TABLE #Calendar
(
Date DATETIME NOT NULL
)
CREATE TABLE #OpenHours
(
Day INT NOT NULL,
OpenFrom TIME NOT NULL,
OpenTo TIME NOT NULL
);
--Fill tables with sample data.
INSERT INTO #OpenHours (Day, OpenFrom, OpenTo)
VALUES
(1, '10:00', '20:00'),
(2, '10:00', '20:00'),
(3, '10:00', '20:00'),
(4, '10:00', '20:00'),
(5, '10:00', '20:00'),
(6, '10:00', '20:00'),
(7, '10:00', '20:00')
DECLARE @CounterDay INT = 0, @CounterHour INT = 0, @Sales NUMERIC(9, 2), @Items INT;
WHILE @CounterDay < 365
BEGIN
SET @CounterHour = 0;
WHILE @CounterHour < 5
BEGIN
SET @Items = CAST(RAND() * 100 AS INT);
SET @Sales = CAST(RAND() * 1000 AS NUMERIC(9, 2));
IF @Items % 2 = 0
BEGIN
SET @Items = NULL;
SET @Sales = NULL;
END
INSERT INTO #Preparation (Date, Hour, Items, Sales)
VALUES (DATEADD(DAY, @CounterDay, '2011-01-01'), @CounterHour + 13, @Items, @Sales);
SET @CounterHour += 1;
END
INSERT INTO #Calendar (Date) VALUES (DATEADD(DAY, @CounterDay, '2011-01-01'));
SET @CounterDay += 1;
END
--Here the query starts.
;WITH P AS (
SELECT DATEADD(HOUR, Hour, Date) AS Hour
,Sales
,Items
FROM #Preparation
),
O AS (
SELECT DISTINCT DATEADD(HOUR, SV.number, C.Date) AS Hour
FROM #OpenHours AS O
JOIN #Calendar AS C ON O.Day = DATEPART(WEEKDAY, C.Date)
JOIN master.dbo.spt_values AS SV ON SV.number BETWEEN DATEPART(HOUR, O.OpenFrom) AND DATEPART(HOUR, O.OpenTo)
),
S AS (
SELECT O.Hour, P.Sales, P.Items
FROM O
LEFT JOIN P ON P.Hour = O.Hour
)
--block comment here case 1 (slow performing)
--With this technique it takes about 34 seconds.
,N AS (
SELECT
A.Hour
,A.Sales AS SalesOrg
,CASE WHEN COALESCE(B.Sales, C.Sales, 1) < 0
THEN 0 ELSE COALESCE(B.Sales, C.Sales, 1) END AS Sales
,A.Items AS ItemsOrg
,COALESCE(B.Items, C.Items, 1) AS Items
FROM S AS A
OUTER APPLY (SELECT TOP 1 *
FROM S
WHERE Hour <= A.Hour
AND Sales IS NOT NULL
AND DATEDIFF(DAY, Hour, A.Hour) = 0
ORDER BY Hour DESC) B
OUTER APPLY (SELECT TOP 1 *
FROM S
WHERE Sales IS NOT NULL
AND DATEDIFF(DAY, Hour, A.Hour) = 0
ORDER BY Hour) C
)
--end block comment here case 1 (slow performing)
/*--block comment here case 2 (fast performing)
--With this technique it takes about 2 seconds.
SELECT * INTO #tmpS FROM S;
WITH
N AS (
SELECT
A.Hour
,A.Sales AS SalesOrg
,CASE WHEN COALESCE(B.Sales, C.Sales, 1) < 0
THEN 0 ELSE COALESCE(B.Sales, C.Sales, 1) END AS Sales
,A.Items AS ItemsOrg
,COALESCE(B.Items, C.Items, 1) AS Items
FROM #tmpS AS A
OUTER APPLY (SELECT TOP 1 *
FROM #tmpS
WHERE Hour <= A.Hour
AND Sales IS NOT NULL
AND DATEDIFF(DAY, Hour, A.Hour) = 0
ORDER BY Hour DESC) B
OUTER APPLY (SELECT TOP 1 *
FROM #tmpS
WHERE Sales IS NOT NULL
AND DATEDIFF(DAY, Hour, A.Hour) = 0
ORDER BY Hour) C
)
--end block comment here case 2 (fast performing)*/
SELECT * FROM N ORDER BY Hour
IF OBJECT_ID('tempdb..#tmpS') IS NOT NULL DROP TABLE #tmpS;
DROP TABLE #Preparation;
DROP TABLE #Calendar;
DROP TABLE #OpenHours;
आप कोशिश करते हैं और समझते हैं कि मैं अंतिम चरण मैं इसे here के बारे में इतना सवाल है में क्या कर रहा हूँ करना चाहते हैं।
मेरे लिए केस 1 में लगभग 34 सेकंड लगते हैं और केस 2 में लगभग 2 सेकंड लगते हैं। अंतर यह है कि मैं 2 से मामले में एक टेम्प तालिका में एस को परिणाम संग्रहीत करता हूं, यदि 1 में मैं अपने अगले सीटीई में सीधे एस का उपयोग करता हूं।
+1 रनने योग्य कोड के लिए। मैं उन्हें एसक्यूएल सेंट्री प्लान एक्सप्लोरर में निष्पादन योजना एक्सएमएल दोनों को चलाने और चिपकाने का सुझाव देता हूं। अंतर का कारण तब स्पष्ट होगा। यह योजना के एक हिस्से में '# तैयारी' 20,000 बार स्कैनिंग और उदाहरण के लिए किसी अन्य भाग में 10,000 बार स्कैनिंग समाप्त होता है। –
धन्यवाद। मैंने एसक्यूएल सेंट्री प्लान एक्सप्लोरर स्थापित किया। मैं अभी भी एसक्यूएल सर्वर सीख रहा हूं और मैं निष्पादन योजनाओं को पढ़ने में सक्षम नहीं हूं, न तो सेंट्री प्लान में। लेकिन जवाब यह है कि निष्पादन योजनाओं की जांच किए बिना कुछ परिदृश्यों में सीटीई या अस्थायी तालिका के साथ सबसे अच्छा यह कहने के बारे में कुछ नहीं कह सकता है? आप 20,000 और 10,000 बार कहां देखते हैं? मुझे यह नहीं मिल रहा है। क्या कोड का जिक्र करते हुए एक भाग स्कैनिंग 20,000 बार क्यों स्कैन कर रहा है, इस बारे में कुछ कहना संभव है? – John
क्या आपने यह देखा है? "एसक्यूएल 2005 सीटीई बनाम टीईएमपी तालिका प्रदर्शन जब अन्य तालिकाओं के जुड़ने में उपयोग किया जाता है" http://stackoverflow.com/questions/1531835/sql-2005-cte-vs-temp-table-performance-when-used-in-joins- अन्य-टेबल –