कुंजी लुकअप (क्लस्टर) ऑपरेटर को हटा दें जो प्रदर्शन धीमा कर देता है


16

मैं अपनी निष्पादन योजना में एक कुंजी लुकअप (क्लस्टर) ऑपरेटर को कैसे समाप्त कर सकता हूं?

तालिका में tblQuotesपहले से ही एक क्लस्टर्ड इंडेक्स (चालू QuoteID) और 27 गैर-अनुक्रमित इंडेक्स हैं, इसलिए मैं किसी और को बनाने की कोशिश नहीं कर रहा हूं।

मैंने QuoteIDअपनी क्वेरी में क्लस्टर किए गए इंडेक्स कॉलम को रखा , उम्मीद है कि यह मदद करेगा - लेकिन दुर्भाग्य से अभी भी वही है।

यहां निष्पादन योजना

या इसे देखें:

यहाँ छवि विवरण दर्ज करें

यह कुंजी लुकअप ऑपरेटर कहता है:

यहाँ छवि विवरण दर्ज करें

प्रश्न:

declare
        @EffDateFrom datetime ='2017-02-01',
        @EffDateTo   datetime ='2017-08-28'

SET NOCOUNT ON
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

IF OBJECT_ID('tempdb..#Data') IS NOT NULL
    DROP TABLE #Data 
CREATE TABLE #Data
(
    QuoteID int NOT NULL,   --clustered index

    [EffectiveDate] [datetime] NULL, --not indexed
    [Submitted] [int] NULL,
    [Quoted] [int] NULL,
    [Bound] [int] NULL,
    [Exonerated] [int] NULL,
    [ProducerLocationId] [int] NULL,
    [ProducerName] [varchar](300) NULL,
    [BusinessType] [varchar](50) NULL,
    [DisplayStatus] [varchar](50) NULL,
    [Agent] [varchar] (50) NULL,
    [ProducerContactGuid] uniqueidentifier NULL
)
INSERT INTO #Data
    SELECT 
        tblQuotes.QuoteID,

          tblQuotes.EffectiveDate,
          CASE WHEN lstQuoteStatus.QuoteStatusID >= 1   THEN 1 ELSE 0 END AS Submitted,
          CASE WHEN lstQuoteStatus.QuoteStatusID = 2 or lstQuoteStatus.QuoteStatusID = 3 or lstQuoteStatus.QuoteStatusID = 202 THEN 1 ELSE 0 END AS Quoted,
          CASE WHEN lstQuoteStatus.Bound = 1 THEN 1 ELSE 0 END AS Bound,
          CASE WHEN lstQuoteStatus.QuoteStatusID = 3 THEN 1 ELSE 0 END AS Exonareted,
          tblQuotes.ProducerLocationID,
          P.Name + ' / '+ P.City as [ProducerName], 
        CASE WHEN tblQuotes.PolicyTypeID = 1 THEN 'New Business' 
             WHEN tblQuotes.PolicyTypeID = 3 THEN 'Rewrite'
             END AS BusinessType,
        tblQuotes.DisplayStatus,
        tblProducerContacts.FName +' '+ tblProducerContacts.LName as Agent,
        tblProducerContacts.ProducerContactGUID
FROM    tblQuotes 
            INNER JOIN lstQuoteStatus 
                on tblQuotes.QuoteStatusID=lstQuoteStatus.QuoteStatusID
            INNER JOIN tblProducerLocations P 
                On P.ProducerLocationID=tblQuotes.ProducerLocationID
            INNER JOIN tblProducerContacts 
                ON dbo.tblQuotes.ProducerContactGuid = tblProducerContacts.ProducerContactGUID

WHERE   DATEDIFF(D,@EffDateFrom,tblQuotes.EffectiveDate)>=0 AND DATEDIFF(D, @EffDateTo, tblQuotes.EffectiveDate) <=0
        AND dbo.tblQuotes.LineGUID = '6E00868B-FFC3-4CA0-876F-CC258F1ED22D'--Surety
        AND tblQuotes.OriginalQuoteGUID is null

select * from #Data

निष्पादन योजना:

यहाँ छवि विवरण दर्ज करें


अनुमानित बनाम वास्तविक पंक्तियों में एक उल्लेखनीय अंतर दिखाई देता है। शायद एसक्यूएल एक बुरी योजना उठा रहा है क्योंकि इसमें अच्छा अनुमान लगाने के लिए डेटा नहीं है। आप अपने आंकड़ों को कितनी बार अपडेट करते हैं?
RDFozz

जवाबों:


23

विभिन्न स्वादों की कुंजी देखने को तब मिलती है जब क्वेरी प्रोसेसर को उन कॉलमों से मान प्राप्त करने की आवश्यकता होती है जो परिणाम वापस करने के लिए क्वेरी के लिए आवश्यक पंक्तियों का पता लगाने के लिए उपयोग किए गए सूचकांक में संग्रहीत नहीं होते हैं।

उदाहरण के लिए निम्न कोड लें, जहां हम एक एकल इंडेक्स के साथ एक टेबल बना रहे हैं:

USE tempdb;

IF OBJECT_ID(N'dbo.Table1', N'U') IS NOT NULL
DROP TABLE dbo.Table1
GO

CREATE TABLE dbo.Table1
(
    Table1ID int NOT NULL IDENTITY(1,1)
    , Table1Data nvarchar(30) NOT NULL
);

CREATE INDEX IX_Table1
ON dbo.Table1 (Table1ID);
GO

हम तालिका में 1,000,000 पंक्तियाँ सम्मिलित करेंगे ताकि हमारे पास काम करने के लिए कुछ डेटा हो:

INSERT INTO dbo.Table1 (Table1Data)
SELECT TOP(1000000) LEFT(c.name, 30)
FROM sys.columns c
    CROSS JOIN sys.columns c1
    CROSS JOIN sys.columns c2;
GO

अब, हम "वास्तविक" निष्पादन योजना को प्रदर्शित करने के विकल्प के साथ डेटा को क्वेरी करेंगे:

SELECT *
FROM dbo.Table1
WHERE Table1ID = 500000;

क्वेरी योजना से पता चलता है:

यहाँ छवि विवरण दर्ज करें

क्वेरी उस IX_Table1सूचकांक को देखने के लिए पंक्ति को ढूंढती है, Table1ID = 5000000क्योंकि उस सूचकांक को देखने से उस मूल्य की तलाश करने वाली संपूर्ण तालिका को स्कैन करने की तुलना में बहुत तेज है। हालाँकि, क्वेरी परिणामों को संतुष्ट करने के लिए, क्वेरी प्रोसेसर को तालिका के अन्य स्तंभों के लिए मान भी खोजना होगा; यह वह जगह है जहाँ "RID लुकअप" आता है। यह स्तंभ Table1IDसे मान प्राप्त करते हुए 500000 के मान वाली पंक्ति से संबद्ध पंक्ति ID (RID लुकअप में RID) के लिए तालिका में दिखता है Table1Data। यदि आप योजना में "RID लुकअप" नोड पर माउस घुमाते हैं, तो आप इसे देखते हैं:

यहाँ छवि विवरण दर्ज करें

"आउटपुट सूची" में RID लुकअप द्वारा दिए गए कॉलम शामिल हैं।

गुच्छेदार सूचकांक और गैर-संकुल सूचकांक वाली तालिका एक दिलचस्प उदाहरण बनाती है। नीचे दी गई तालिका में तीन कॉलम हैं; आईडी जो क्लस्टरिंग कुंजी है, Datजो एक गैर-क्लस्टर इंडेक्स IX_Tableऔर एक तीसरे कॉलम द्वारा अनुक्रमित है Oth

USE tempdb;

IF OBJECT_ID(N'dbo.Table1', N'U') IS NOT NULL
DROP TABLE dbo.Table1
GO

CREATE TABLE dbo.Table1
(
    ID int NOT NULL IDENTITY(1,1) 
        PRIMARY KEY CLUSTERED
    , Dat nvarchar(30) NOT NULL
    , Oth nvarchar(3) NOT NULL
);

CREATE INDEX IX_Table1
ON dbo.Table1 (Dat);
GO

INSERT INTO dbo.Table1 (Dat, Oth)
SELECT TOP(1000000) CRYPT_GEN_RANDOM(30), CRYPT_GEN_RANDOM(3)
FROM sys.columns c
    CROSS JOIN sys.columns c1
    CROSS JOIN sys.columns c2;
GO

इस उदाहरण को लें:

SELECT *
FROM dbo.Table1
WHERE Dat = 'Test';

हम SQL सर्वर से उस कॉलम के हर कॉलम को वापस करने के लिए कह रहे हैं जहाँ Datकॉलम में शब्द है Test। हमारे पास यहां कुछ विकल्प हैं; हम तालिका (यानी संकुल अनुक्रमणिका) देख सकते हैं - लेकिन यह है कि पूरी बात को स्कैन करने के बाद तालिका द्वारा आदेश दिया है करना पड़ेगा IDस्तंभ है, जो हमें कुछ भी नहीं है जिसके बारे में पंक्ति (यों) में बताता Testमें Datस्तंभ। अन्य विकल्प (और SQL सर्वर द्वारा चुना गया) IX_Table1में पंक्ति को खोजने के लिए गैर-क्लस्टर इंडेक्स में मांग करना शामिल है Dat = 'Test', हालांकि, चूंकि हमें Othकॉलम की भी आवश्यकता है , SQL सर्वर को "कुंजी का उपयोग करके क्लस्टर इंडेक्स में एक लुकअप करना चाहिए। लुकअप ”ऑपरेशन। यह उस के लिए योजना है:

यहाँ छवि विवरण दर्ज करें

हम ऐसा गैर-संकुल अनुक्रमणिका को संशोधित कि यह तो शामिलOth कॉलम:

DROP INDEX IX_Table1
ON dbo.Table1;
GO

CREATE INDEX IX_Table1
ON dbo.Table1 (Dat)
INCLUDE (Oth);        <---- This is the only change
GO

फिर क्वेरी फिर से चलाएँ:

SELECT *
FROM dbo.Table1
WHERE Dat = 'Test';

अब हम एक गैर संकुल अनुक्रमणिका की तलाश के बाद से एसक्यूएल सर्वर बस जहां पंक्ति का पता लगाने की जरूरत है देखने Dat = 'Test'में IX_Table1सूचकांक है, जो के लिए मूल्य भी शामिल है Othऔर के लिए मूल्य, IDस्तंभ (प्राथमिक कुंजी) है, जो हर गैर में स्वचालित रूप से मौजूद है गुच्छेदार सूचकांक। योजना:

यहाँ छवि विवरण दर्ज करें


6

कुंजी लुकअप के कारण होता है क्योंकि इंजन ने एक अनुक्रमणिका का उपयोग करने के लिए चुना है जिसमें आपके द्वारा लाए जा रहे सभी कॉलम शामिल नहीं हैं। इसलिए सूचकांक चयन और जहां कथन में कॉलम को कवर नहीं कर रहा है।

कुंजी लुकअप को समाप्त करने के लिए आपको कॉलम (कुंजी लुकअप की आउटपुट सूची में कॉलम) को शामिल करने की आवश्यकता है।

ध्यान दें कि एक मेज पर 27 गैर-संकुल सूचकांक प्रदर्शन के लिए खराब हो सकते हैं। अद्यतन चलाते समय, सम्मिलित करें या हटाएं, SQL सर्वर को सभी अनुक्रमित को अद्यतन करना चाहिए। यह अतिरिक्त कार्य प्रदर्शन को नकारात्मक रूप से प्रभावित कर सकता है।


यह भी ध्यान दें कि बहुत से सूचकांक निष्पादन योजना के संकलन को भ्रमित कर सकते हैं, और इसके परिणामस्वरूप उप-इष्टतम चयन भी हो सकते हैं।
यह उतार चढ़ाव भरा

4

आप इस क्वेरी में शामिल डेटा की मात्रा का उल्लेख करना भूल गए। इसके अलावा आप एक टेम्‍प टेबल में क्‍यों डाल रहे हैं? यदि केवल आपको प्रदर्शित करने की आवश्यकता है तो सम्मिलित विवरण न चलाएं।

इस क्वेरी के प्रयोजनों के लिए, tblQuotes27 गैर-संकुल सूचकांक की आवश्यकता नहीं है। इसमें 1 क्लस्टर इंडेक्स और 5 नॉन-क्लस्टर्ड इंडेक्स या, शायद 6 नॉन-क्लस्टर्ड इंडेक्स की जरूरत है।

यह प्रश्न इन स्तंभों पर अनुक्रमित करना चाहेंगे:

QuoteStatusID
ProducerLocationID
ProducerContactGuid
EffectiveDate
LineGUID
OriginalQuoteGUID

मैंने निम्नलिखित कोड भी देखा:

DATEDIFF(D, @EffDateFrom, tblQuotes.EffectiveDate) >= 0 AND 
DATEDIFF(D, @EffDateTo, tblQuotes.EffectiveDate) <= 0

है NON Sargableयानी यह अनुक्रमित का उपयोग नहीं कर सकते हैं।

उस कोड को SARgableइसे इस में बदलने के लिए:

tblQuotes.EffectiveDate >= @EffDateFrom 
AND  tblQuotes.EffectiveDate <= @EffDateFrom

अपने मुख्य प्रश्न का उत्तर देने के लिए, "आपको एक कुंजी क्यों दिख रही है":

आपको मिल रहा है KEY Look upक्योंकि क्वेरी में उल्लिखित कुछ कॉलम कवरिंग इंडेक्स में मौजूद नहीं हैं।

आप Google और के बारे में अध्ययन कर सकते हैं Covering Indexया कर सकते हैं Include index

मेरे उदाहरण में मान लीजिए कि tblQuotes.QuoteStatusID नॉन क्लस्टर्ड इंडेक्स है तो मैं DisplayStatus को भी कवर कर सकता हूं। चूंकि आप Resultset में DisplayStatus चाहते हैं। कोई भी कॉलम जो इंडेक्स में मौजूद नहीं है और परिणामी में मौजूद है उसे बचने के लिए कवर किया जा सकता है KEY Look Up or Bookmark lookup। यह सूचकांक को कवर करने वाला एक उदाहरण है:

create nonclustered index tblQuotes_QuoteStatusID 
on tblQuotes(QuoteStatusID)
include(DisplayStatus);

** अस्वीकरण: ** ऊपर याद रखें केवल मेरा उदाहरण है DisplayStatus विश्लेषण के बाद अन्य गैर सीआई के साथ कवर किया जा सकता है।

इसी तरह आपको क्वेरी में शामिल अन्य तालिकाओं पर सूचकांक और कवरिंग इंडेक्स बनाना होगा।

आप Index SCANअपनी योजना में भी शामिल हो रहे हैं ।

ऐसा इसलिए हो सकता है क्योंकि टेबल पर कोई इंडेक्स नहीं है या जब बड़ी मात्रा में डेटा होता है तो ऑप्टिमाइज़र इंडेक्स की तलाश करने के बजाय स्कैन करने का निर्णय ले सकता है।

इसके कारण भी हो सकता है High cardinality। दोषपूर्ण जुड़ने के कारण आवश्यकता से अधिक पंक्तियों को प्राप्त करना। इसे भी ठीक किया जा सकता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.