2010-01-03 13 views
6

का उपयोग करते समय तेज़ क्वेरी परिणाम के लिए डेटाबेस स्कीमा/इंडेक्स को अनुकूलित करें SQL सर्वर सर्वर डेटाबेस पर पेड़ संरचना को लागू करते समय, क्वेरी प्रतिक्रिया बहुत लंबी लग रही है (नीचे प्रश्न 5 सेकंड से अधिक बात कर रहे हैं) का उपयोग करते समय EXISTS क्लॉज के साथ संयुक्त खंड की तरह। [UserSiteRight_T] में के लिए UserID_i = 2484LIKE और EXISTS क्लॉज

CREATE TABLE [dbo].[UserSiteRight_T](
     [UserID_i] [int] NOT NULL 
    , [SiteID_i] [int] NOT NULL 
    , CONSTRAINT [PKC_UserSiteRight_UserIDSiteID] PRIMARY KEY CLUSTERED ([UserID_i] ASC, [SiteID_i] ASC) 
    , CONSTRAINT [FK_UserSiteRight_UserID] FOREIGN KEY([UserID_i]) REFERENCES [dbo].[User_T] ([ID_i]) 
    , CONSTRAINT [FK_UserSiteRight_SiteID] FOREIGN KEY([SiteID_i]) REFERENCES [dbo].[Site_T] ([ID_i]) 
) 

पंक्तियों की संख्या (अधिकार): [SitePath_T] और [UserSiteRight_T] -

धीमी गति से प्रश्नों दो तालिकाओं शामिल तालिका काफी छोटी है: 545
(उपयोगकर्ता आईडी_आई = 2484 यादृच्छिक रूप से चुना गया था)

इसके अलावा, डेटाबेस अपेक्षाकृत छोटा है - [SitePath_T] तालिका में केवल 23,000 पंक्तियाँ:

CREATE TABLE [dbo].[SitePath_T] (
    [SiteID_i] INT NOT NULL, 
    [Path_v] VARCHAR(255) NOT NULL, 
    CONSTRAINT [PK_SitePath_PathSiteID] PRIMARY KEY CLUSTERED ([Path_v] ASC, [SiteID_i] ASC), 
    CONSTRAINT [AK_SitePath_Path] UNIQUE NONCLUSTERED ([Path_v] ASC), 
    CONSTRAINT [FK_SitePath_SiteID] FOREIGN KEY([SiteID_i]) REFERENCES [Site_T] ([ID_i]) 


DB Schema http://i46.tinypic.com/258aqfm.png

मैं पाने के लिए कोशिश कर रहा हूँ) केवल साइट आईडी जो accessib accessib है le एक निश्चित UserID ([UserSiteRight_T] तालिका द्वारा दिए गए) के रूप में द्वारा:

SELECT sp.SiteID_i 
    FROM SitePath_t sp 
WHERE EXISTS (SELECT * 
       FROM [dbo].[SitePath_T] usp 
       , [dbo].[UserSiteRight_T] uusr 
      WHERE uusr.SiteID_i = usp.SiteID_i 
       AND uusr.UserID_i = 2484 
       AND usp.Path_v LIKE sp.Path_v+'%') 

आप नीचे परिणाम जहां केवल स्तंभ sp.SiteID_i की जरूरत है का एक हिस्सा मिल सकता है/लौटे - भी मैं जोड़ा संबंधित संबंधित Path_v, UserSiteRight_T।SiteID_iकहां UserID = 2484 और इसी SitePath_TSiteID_i और Path_vतरह हालत मिलान:

|--Nested Loops(Left Semi Join, WHERE:([MyTestDB].[dbo].[SitePath_T].[Path_v] as [usp].[Path_v] like [Expr1007])) 
     |--Compute Scalar(DEFINE:([Expr1007]=[MyTestDB].[dbo].[SitePath_T].[Path_v] as [sp].[Path_v]+'%', [Expr1008]=LikeRangeStart([MyTestDB].[dbo].[SitePath_T].[Path_v] as [sp].[Path_v]+'%'), [Expr1009]=LikeRangeEnd([MyTestDB].[dbo].[SitePath_T].[Path_v] as [sp].[Path_v]+'%'), [Expr1010]=LikeRangeInfo([MyTestDB].[dbo].[SitePath_T].[Path_v] as [sp].[Path_v]+'%'))) 
     | |--Index Scan(OBJECT:([MyTestDB].[dbo].[SitePath_T].[AK_SitePath_Path] AS [sp])) 
     |--Table Spool 
      |--Hash Match(Inner Join, HASH:([uusr].[SiteID_i])=([usp].[SiteID_i])) 
       |--Clustered Index Seek(OBJECT:([MyTestDB].[dbo].[UserSiteRight_T].[PKC_UserSiteRight_UserIDSiteID] AS [uusr]), SEEK:([uusr].[UserID_i]=(2484)) ORDERED FORWARD) 
       |--Index Scan(OBJECT:([MyTestDB].[dbo].[SitePath_T].[AK_SitePath_Path] AS [usp])) 
: उपरोक्त क्वेरी के लिए

sp.SiteID_i sp.Path_v  [UserSiteRight_T].SiteID_i  usp.SiteID_i  usp.Path_v 
1   '1.'      NULL    10054    '1.10054.' 
10054  '1.10054.'     10054    10054    '1.10054.' 
10275  '1.10275.'     10275    10275    '1.10275.' 
1533  '1.1533.'     NULL    2697    '1.1533.2689.2693.2697.' 
2689  '1.1533.2689.'    NULL    2697    '1.1533.2689.2693.2697.' 
2693  '1.1533.2689.2693.'   NULL    2697    '1.1533.2689.2693.2697.' 
2697  '1.1533.2689.2693.2697.' 2697    2697    '1.1533.2689.2693.2697.' 
1580  '1.1580.'     NULL    1581    '1.1580.1581.' 
1581  '1.1580.1581.'    1581    1581    '1.1580.1581.' 
1585  '1.1580.1581.1585.'   1585    1585    '1.1580.1581.1585.' 
222   '1.222.'     222     222     '1.222.' 
223   '1.222.223.'    223     223     '1.222.223.' 
224   '1.222.223.224.'   224     224     '1.222.223.224.' 
3103  '1.3103.'     NULL    3537    '1.3103.3529.3533.3537.' 
3529  '1.3103.3529.'    NULL    3537    '1.3103.3529.3533.3537.' 
3533  '1.3103.3529.3533.'   NULL    3537    '1.3103.3529.3533.3537.' 
3537  '1.3103.3529.3533.3537.' 3537    3537    '1.3103.3529.3533.3537.' 

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

और पुनः लिखित क्वेरी:

SELECT DISTINCT 
     sp.SiteID_i 
    FROM [dbo].[SitePath_t] sp 
    , [dbo].[SitePath_T] usp 
    , [dbo].[UserSiteRight_T] uusr 
WHERE (uusr.SiteID_i = usp.SiteID_i 
    AND uusr.UserID_i = 2484 
    AND usp.Path_v LIKE sp.Path_v+'%') 
ORDER BY SiteID_i ASC 

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

|--Hash Match(Aggregate, HASH:([sp].[SiteID_i])) 
     |--Nested Loops(Inner Join, WHERE:([MyTestDB].[dbo].[SitePath_T].[Path_v] as [usp].[Path_v] like [Expr1006])) 
      |--Hash Match(Inner Join, HASH:([uusr].[SiteID_i])=([usp].[SiteID_i])) 
      | |--Clustered Index Seek(OBJECT:([MyTestDB].[dbo].[UserSiteRight_T].[PKC_UserSiteRight_UserIDSiteID] AS [uusr]), SEEK:([uusr].[UserID_i]=(2484)) ORDERED FORWARD) 
      | |--Index Scan(OBJECT:([MyTestDB].[dbo].[SitePath_T].[AK_SitePath_Path] AS [usp])) 
      |--Table Spool 
       |--Compute Scalar(DEFINE:([Expr1006]=[MyTestDB].[dbo].[SitePath_T].[Path_v] as [sp].[Path_v]+'%', [Expr1007]=LikeRangeStart([MyTestDB].[dbo].[SitePath_T].[Path_v] as [sp].[Path_v]+'%'), [Expr1008]=LikeRangeEnd([MyTestDB].[dbo].[SitePath_T].[Path_v] as [sp].[Path_v]+'%'), [Expr1009]=LikeRangeInfo([MyTestDB].[dbo].[SitePath_T].[Path_v] as [sp].[Path_v]+'%'))) 
         |--Index Scan(OBJECT:([MyTestDB].[dbo].[SitePath_T].[AK_SitePath_Path] AS [sp])) 

सभी अनुक्रमित स्थान पर हैं - डेटाबेस इंजन ट्यूनिंग सलाहकार नई स्कीमा संशोधन के प्रस्ताव दिए नहीं है - लेकिन दोनों प्रश्नों अधिक है कि 5 सेकंड में सही परिणाम लौट रहे हैं - और , क्योंकि यह एक अजाक्स की प्रतिक्रिया है - नेविगेशन पेड़ को अपडेट करते समय (और है) बहुत धीमा लगता है

तेज प्रतिक्रिया प्राप्त करने के लिए डेटाबेस स्कीमा/इंडेक्स/क्वेरी को अनुकूलित/संशोधित करने के लिए कोई सुझाव?

धन्यवाद

+0

मुझे आश्चर्य है अगर साइटों के लिए एक पुनरावर्ती CTE बेहतर होगा, लेकिन मैं अपने डेटा से नहीं बता सकता पता है कि कैसे क्या जड़ 'SITEPATH_T' मान हैं। –

उत्तर

3

के आधार पर:

SELECT sp.SiteID_i 
    FROM SitePath_t sp 
WHERE EXISTS (SELECT * 
       FROM [dbo].[SitePath_T] usp 
       , [dbo].[UserSiteRight_T] uusr 
      WHERE uusr.SiteID_i = usp.SiteID_i 
       AND uusr.UserID_i = 2484 
       AND usp.Path_v LIKE sp.Path_v+'%') 

(जो ठीक तथ्य पर आधारित है कि आप क्या कर रहे हैं कि एक अर्ध शामिल हों)।

यह उपयोगकर्ता के रिकॉर्ड्स को खोजने के लिए पहले यूज़र तालिका पर ध्यान केंद्रित कर रहा है। यह पहले से ही एक सीईक्स खोज कर रहा है, जो अच्छा है। वहां से, यह साइटआईडी_आई फ़ील्ड के अनुसार यूएसपी में संबंधित रिकॉर्ड ढूंढ रहा है।

तो अगली बार इस तथ्य पर विचार करें कि यह SiteID_i द्वारा साइटें खोजना चाहता है, और आप किस तरह के शामिल होना चाहते हैं।

विलय के बारे में कैसे शामिल हों? यह अच्छा होगा, लेकिन डेटा को दोनों तरफ क्रमबद्ध करने की आवश्यकता है। यह ठीक है अगर इंडेक्स सही क्रम में हैं ...

... और उसके बाद, आप पथ के आधार पर सामान ढूंढना चाहते हैं।तो कैसे के बारे में:

CREATE INDEX ix_UUSR on [dbo].[UserSiteRight_T] (UserID_i, SiteID_i); 
CREATE INDEX ix_usp on [dbo].[SitePath_T] (SiteID_i) INCLUDE (Path_v); 

और फिर SitePath_T पर एक और सूचकांक कि SiteIDs आप चाहते हैं पाता है:

CREATE INDEX ix_sp on [dbo].[SitePath_T] (Path_v) INCLUDE (SiteID_i); 

एक नेस्टेड लूप इस अंतिम एक पर इस्तेमाल किया हो सकता है, लेकिन यह है कि उम्मीद है कि बहुत बुरा नहीं है। जो चीज आपके सिस्टम को प्रभावित करने जा रही है वह पहली दो इंडेक्स होगी, जो आपको अपने EXISTS क्लॉज में दो तालिकाओं के बीच विलय में शामिल होने देनी चाहिए।

+0

तो ... इस तथ्य के बारे में सोचें कि आप साइटआईआई_आई ऑर्डर में आने वाली पंक्तियों को चाहते हैं, और यूपी से बाहर आने वाली पंक्तियां उसी क्रम में होंगी, जो अत्यधिक शामिल होने में मदद करेगी। तब आपके पास पथ हैं, और वहां अभी भी कुछ दर्द हो सकता है, लेकिन संभावित रूप से बहुत अधिक नहीं है। –

+0

मैं यह भी कहने जा रहा था, "SitePath_T (Path_v) पर एक कवरिंग इंडेक्स फेंक दें", लेकिन उसे पहले से ही एक डब्ल्यू/गैर-क्लस्टरर्ड अद्वितीय बाधा मिली है। यह अभी भी एक सूचकांक स्कैन करता है! तो प्रश्न बनी हुई है, हम निष्पादन योजना में जितनी जल्दी हो सके डेटा वॉल्यूम को कम कर सकते हैं? –

+0

हाय रोब, साइटपैथ_टी पर दो इंडेक्स की बजाय हमारे पास प्रभाव होने के लिए उत्सुकता है, हमारे पास केवल एक ...... इंडेक्स ix_sp [dbo] पर बनाएं। [SitePath_T] (Path_v, SiteID_i); पथ_वी को ध्यान में रखते हुए अधिक फ़िल्टरिंग हो सकती है, इसलिए हम पहले फ़िल्टर करेंगे और फिर विलय में शामिल होंगे। अगर मैं गलत हूं कृपया मुझे सही। मेरी राय में यदि हम समग्र इंडेक्स का उपयोग कर पारंपरिक रूप से देख सकते हैं, तो हमें ऐसा करना चाहिए। –

0

मैं अपने UserSiteRight_T तालिका में विदेशी कुंजी पर एक सूचकांक जोड़ने का प्रयास करते हैं - वे कर रहे हैं अभी तक अनुक्रमित नहीं है, और उन क्षेत्रों पर एक सूचकांक लुकअप में तेजी लाने चाहिए:

CREATE NONCLUSTERED INDEX IX01_UserSiteRight 
    ON UserSiteRight_T(UserID_i) 

CREATE NONCLUSTERED INDEX IX02_UserSiteRight 
    ON UserSiteRight_T(SiteID_i) 

और अपने SitePath_T मेज पर साथ ही:

CREATE NONCLUSTERED INDEX IX01_SitePath 
    ON dbo.SitePath_T(SiteID_i) 

कोशिश जगह में इन डाल करने के लिए है, तो आपके प्रश्नों को पुन: चलाने, और चलाने के समय और निष्पादन योजनाओं की तुलना - कर यो आप कोई सुधार देखते हैं ??

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

0

माता-पिता आपको ढूंढने के लिए साइटपैथ_T पर स्वयं शामिल हो जाते हैं। शायद आपको ParentSiteID_i के लिए एक कॉलम जोड़ना चाहिए और एक सामान्य रिकर्सिव सीटीई का उपयोग करना चाहिए?

तो यह हो जाता है:

WITH Recurse_CTE AS (
    SELECT 
    us.SiteID_i 
    , us.ParentSiteID_i 
    , 0 AS RecurseDepth_i 
    FROM dbo.SitePath_T us 
    JOIN dbo.UserSiteRight_T uusr ON us.SiteID_i = uusr.SiteID_i 
    WHERE uusr.UserID_i = 2484 
    UNION ALL 
    SELECT 
    us.SiteID_i 
    , us.ParentSiteID_i 
    , rcs.RecurseDepth_i+1 AS RecurseDepth_i 
    FROM dbo.SitePath_T us 
    JOIN Recurse_CTE rcs ON us.SiteID_i = rcs.ParentSiteID_i 
) 
SELECT * FROM Recurse_CTE 

SitePath_T (ParentSiteID_i) पर एक सूचकांक फेंक और प्रदर्शन तेज़ होना चाहिए।

0

मैं स्कीमा/एल्गोरिदम को समझने और अनुक्रमण स्कीमा प्रदान करने के लिए Rob Farley पर क्रेडिट देना भी चाहूंगा।

लेकिन समस्या इंडेक्सिंग स्कीमा नहीं है।

यह प्रश्न अनुकूलक है!

इसके बारे में अधिक इस फॉलोअप पोस्ट में: SQL Server 2005 T-SQL Problem : Can you trust the Query Optimizer ? I know I can't !