आमतौर पर, मैं सभी मानक कारणों के लिए सम्मिलित संकेत का उपयोग करने के खिलाफ सलाह देता हूं। हाल ही में, हालांकि, मुझे एक पैटर्न मिला है जहां मैं लगभग हमेशा बेहतर प्रदर्शन करने के लिए एक मजबूर पाश में शामिल होता हूं। वास्तव में, मैं इसका उपयोग और सिफारिश करने लगा हूं कि मैं यह सुनिश्चित करने के लिए एक दूसरी राय प्राप्त करना चाहता हूं कि मुझे कुछ याद नहीं है। यहां एक प्रतिनिधि परिदृश्य है (उदाहरण के लिए एक विशिष्ट कोड अंत में है):
--Case 1: NO HINT
SELECT S.*
INTO #Results
FROM #Driver AS D
JOIN SampleTable AS S ON S.ID = D.ID
--Case 2: LOOP JOIN HINT
SELECT S.*
INTO #Results
FROM #Driver AS D
INNER LOOP JOIN SampleTable AS S ON S.ID = D.ID
सैंपलटेबल की 1 मिलियन पंक्तियाँ हैं और इसकी पीके आईडी है।
Temp तालिका #Driver में केवल एक कॉलम, ID, कोई अनुक्रमणिका और 50K पंक्तियाँ नहीं हैं।
मुझे लगातार जो मिल रहा है वह निम्नलिखित है:
केस 1:
सैंपलटेबल
हैश
पर NO HINT इंडेक्स स्कैन उच्च अवधि (avg 333ms)
उच्च CPU (औसत 331ms)
लोअर लॉजिकल रीड्स (4714) में शामिल हों
केस 2:
सैंपल
लूप
पर लोएप ज्वाइंट हंट इंडेक्स लोअर ड्यूरेशन (एवीजी 204ms, 39% कम)
लोअर सीपीयू ( एवीजी 206, 38% कम)
ज्यादा हायर लॉजिकल रीड्स (160015, 34X अधिक) में शामिल हों।
सबसे पहले, दूसरे मामले की बहुत अधिक रीडिंग ने मुझे थोड़ा डरा दिया क्योंकि रीडिंग कम करना अक्सर प्रदर्शन का एक अच्छा उपाय माना जाता है। लेकिन जितना मैं सोचता हूं कि वास्तव में क्या हो रहा है, यह मुझे चिंतित नहीं करता है। यहाँ मेरी सोच है:
नमूनाटैब 4714 पृष्ठों पर सम्मिलित है, जो लगभग 36 एमबी है। केस 1 उन सभी को स्कैन करता है जिसके कारण हमें 4714 रीड मिलते हैं। इसके अलावा, इसे 1 मिलियन हैश करना चाहिए, जो सीपीयू गहन हैं, और जो अंततः समय को आनुपातिक रूप से बढ़ाता है। यह सब हैशिंग है जो केस 1 में समय बढ़ाता है।
अब मामला 2 पर विचार करें। यह कोई हैशिंग नहीं कर रहा है, बल्कि यह 50000 अलग-अलग शोध कर रहा है, जो कि रीड्स को बढ़ा रहा है। लेकिन तुलनात्मक रूप से रीड कितने महंगे हैं? कोई कह सकता है कि अगर वे शारीरिक पढ़े लिखे हैं, तो यह काफी महंगा हो सकता है। लेकिन ध्यान रखें 1) दिए गए पृष्ठ का केवल पहला पाठ भौतिक हो सकता है, और 2) यहां तक कि, केस 1 में भी वही या इससे भी बदतर समस्या होगी क्योंकि यह हर पृष्ठ को हिट करने की गारंटी है।
इस तथ्य के लिए लेखांकन कि दोनों मामलों में कम से कम एक बार प्रत्येक पृष्ठ तक पहुंच है, ऐसा लगता है कि यह एक सवाल है जो तेज है, 1 मिलियन हैश या लगभग 155000 मेमोरी के खिलाफ पढ़ता है? मेरे परीक्षण बाद में कहने लगते हैं, लेकिन SQL सर्वर लगातार पूर्व को चुनता है।
सवाल
तो अपने प्रश्न पर वापस: क्या मुझे इस प्रकार के जॉइंट संकेत को जारी रखना चाहिए जब परीक्षण इस प्रकार के परिणाम दिखाता है, या क्या मैं अपने विश्लेषण में कुछ याद कर रहा हूं? मैं एसक्यूएल सर्वर के ऑप्टिमाइज़र के खिलाफ जाने में संकोच कर रहा हूं, लेकिन ऐसा महसूस होता है कि इन जैसे मामलों में इसे पहले की तुलना में हैश ज्वाइन का उपयोग करने के लिए स्विच करता है।
अपडेट 2014-04-28
मैंने कुछ और परीक्षण किए, और पता चला कि जो परिणाम मैं (एक वीएम डब्ल्यू / 2 सीपीयू पर) प्राप्त कर रहा था, मैं अन्य वातावरण में दोहरा नहीं सकता था (मैंने 8 और 12 सीपीयू के साथ 2 अलग-अलग भौतिक मशीनों पर कोशिश की)। ऑप्टिमाइज़र ने बाद के मामलों में उस बिंदु पर बहुत बेहतर किया, जहां ऐसा कोई स्पष्ट मुद्दा नहीं था। मुझे लगता है कि सबक सीखा, जो पूर्वव्यापी में स्पष्ट लगता है, यह है कि पर्यावरण काफी हद तक प्रभावित कर सकता है कि अनुकूलक कितना अच्छा काम करता है।
निष्पादन योजनाएं
निष्पादन योजना प्रकरण 1 निष्पादन योजना प्रकरण 2
नमूना मामला उत्पन्न करने के लिए कोड
------------------------------------------------------------
-- 1. Create SampleTable with 1,000,000 rows
------------------------------------------------------------
CREATE TABLE SampleTable
(
ID INT NOT NULL PRIMARY KEY CLUSTERED
, Number1 INT NOT NULL
, Number2 INT NOT NULL
, Number3 INT NOT NULL
, Number4 INT NOT NULL
, Number5 INT NOT NULL
)
--Add 1 million rows
;WITH
Cte0 AS (SELECT 1 AS C UNION ALL SELECT 1), --2 rows
Cte1 AS (SELECT 1 AS C FROM Cte0 AS A, Cte0 AS B),--4 rows
Cte2 AS (SELECT 1 AS C FROM Cte1 AS A ,Cte1 AS B),--16 rows
Cte3 AS (SELECT 1 AS C FROM Cte2 AS A ,Cte2 AS B),--256 rows
Cte4 AS (SELECT 1 AS C FROM Cte3 AS A ,Cte3 AS B),--65536 rows
Cte5 AS (SELECT 1 AS C FROM Cte4 AS A ,Cte2 AS B),--1048576 rows
FinalCte AS (SELECT ROW_NUMBER() OVER (ORDER BY C) AS Number FROM Cte5)
INSERT INTO SampleTable
SELECT Number, Number, Number, Number, Number, Number
FROM FinalCte
WHERE Number <= 1000000
------------------------------------------------------------
-- Create 2 SPs that join from #Driver to SampleTable.
------------------------------------------------------------
GO
IF OBJECT_ID('JoinTest_NoHint') IS NOT NULL DROP PROCEDURE JoinTest_NoHint
GO
CREATE PROC JoinTest_NoHint
AS
SELECT S.*
INTO #Results
FROM #Driver AS D
JOIN SampleTable AS S ON S.ID = D.ID
GO
IF OBJECT_ID('JoinTest_LoopHint') IS NOT NULL DROP PROCEDURE JoinTest_LoopHint
GO
CREATE PROC JoinTest_LoopHint
AS
SELECT S.*
INTO #Results
FROM #Driver AS D
INNER LOOP JOIN SampleTable AS S ON S.ID = D.ID
GO
------------------------------------------------------------
-- Create driver table with 50K rows
------------------------------------------------------------
GO
IF OBJECT_ID('tempdb..#Driver') IS NOT NULL DROP TABLE #Driver
SELECT ID
INTO #Driver
FROM SampleTable
WHERE ID % 20 = 0
------------------------------------------------------------
-- Run each test and run Profiler
------------------------------------------------------------
GO
/*Reg*/ EXEC JoinTest_NoHint
GO
/*Loop*/ EXEC JoinTest_LoopHint
------------------------------------------------------------
-- Results
------------------------------------------------------------
/*
Duration CPU Reads TextData
315 313 4714 /*Reg*/ EXEC JoinTest_NoHint
309 296 4713 /*Reg*/ EXEC JoinTest_NoHint
327 329 4713 /*Reg*/ EXEC JoinTest_NoHint
398 406 4715 /*Reg*/ EXEC JoinTest_NoHint
316 312 4714 /*Reg*/ EXEC JoinTest_NoHint
217 219 160017 /*Loop*/ EXEC JoinTest_LoopHint
211 219 160014 /*Loop*/ EXEC JoinTest_LoopHint
217 219 160013 /*Loop*/ EXEC JoinTest_LoopHint
190 188 160013 /*Loop*/ EXEC JoinTest_LoopHint
187 187 160015 /*Loop*/ EXEC JoinTest_LoopHint
*/