कुशलता से बड़े सेटों को फ़िल्टर करें


9

मान लीजिए कि मेरे पास एक एकल तालिका है

CREATE TABLE Ticket (
    TicketId int NOT NULL,
    InsertDateTime datetime NOT NULL,
    SiteId int NOT NULL,
    StatusId tinyint NOT NULL,
    AssignedId int NULL,
    ReportedById int NOT NULL,
    CategoryId int NULL
);

इस उदाहरण TicketIdमें प्राथमिक कुंजी है।

मैं चाहता हूं कि उपयोगकर्ता इस तालिका के विरुद्ध "आंशिक रूप से तदर्थ" क्वेरी बनाने में सक्षम हों। मैं आंशिक रूप से कहता हूं क्योंकि क्वेरी के कुछ हिस्से हमेशा तय होंगे:

  1. क्वेरी हमेशा a पर एक श्रेणी फ़िल्टर करेगीInsertDateTime
  2. क्वेरी हमेशा रहेगी ORDER BY InsertDateTime DESC
  3. क्वेरी पृष्ठ परिणाम देगा

उपयोगकर्ता वैकल्पिक रूप से किसी अन्य कॉलम पर फ़िल्टर कर सकता है। वे कोई नहीं, एक, या कई पर फ़िल्टर कर सकते हैं। और प्रत्येक स्तंभ के लिए उपयोगकर्ता मानों के एक सेट से चुन सकता है जिसे एक विघटन के रूप में लागू किया जाएगा। उदाहरण के लिए:

SELECT
    TicketId
FROM (
    SELECT
        TicketId,
        ROW_NUMBER() OVER(ORDER BY InsertDateTime DESC) as RowNum
    FROM Ticket
    WHERE InsertDateTime >= '2013-01-01' AND InsertDateTime < '2013-02-01'
      AND StatusId IN (1,2,3)
      AND (CategoryId IN (10,11) OR CategoryId IS NULL)
    ) _
WHERE RowNum BETWEEN 1 AND 100;

अब मान लें कि तालिका में 100,000,000 पंक्तियाँ हैं।

सबसे अच्छा मैं आ सकता है एक कवरिंग इंडेक्स जिसमें "वैकल्पिक" कॉलम में से प्रत्येक शामिल है:

CREATE NONCLUSTERED INDEX IX_Ticket_Covering ON Ticket (
    InsertDateTime DESC
) INCLUDE (
    SiteId, StatusId, AssignedId, ReportedById, CategoryId
);

यह मुझे एक क्वेरी प्लान इस प्रकार देता है:

  • चुनते हैं
    • फ़िल्टर
      • ऊपर
        • अनुक्रम परियोजना (गणना स्केलर)
          • खंड
            • सूचकांक की तलाश

यह बहुत अच्छा लगता है। लगभग 80% -90% लागत इंडेक्स सीक ऑपरेशन से आती है, जो आदर्श है।

क्या इस तरह की खोज को लागू करने के लिए बेहतर रणनीतियां हैं?

मैं जरूरी नहीं कि ग्राहक के लिए वैकल्पिक फ़िल्टरिंग को उतारना चाहता हूं क्योंकि कुछ मामलों में "निश्चित" भाग से सेट किया गया परिणाम 100 सेकंड या उससे अधिक हो सकता है। क्लाइंट तब सॉर्टिंग और पेजिंग के लिए भी जिम्मेदार होगा जो क्लाइंट के लिए बहुत काम कर सकता है।


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

@ वल्करी जो अविश्वसनीय रूप से अक्षम लगती है। यह भी विचार करें कि इस क्वेरी के वेरिएंट (अलग-अलग पैरामीटर और अलग-अलग वैकल्पिक जहां क्लॉस होते हैं) संभवतः दिन भर में कई बार एक दूसरे को निष्पादित करेंगे और 100 से कम समय में औसतन परिणाम वापस करने की आवश्यकता होगी। हम पहले से ही ऐसा करते हैं, और यह अभी के लिए ठीक है। मैं सिर्फ मापनीयता के लिए प्रदर्शन में सुधार करने के लिए जारी रखने के बारे में विचारों की तलाश कर रहा हूं।
जोसेफ Daigle

स्टोरेज स्पेस का उपयोग करने के बारे में आप कितना ध्यान रखते हैं?
जॉन सेगेल

@JonSeigel यह निर्भर करता है कि कितना ... लेकिन मैं किसी भी सुझाव को देखना चाहता हूं
जोसेफ Daigle

2
और परिणामों के 2 पृष्ठ प्राप्त करने के लिए आपका दृष्टिकोण / क्वेरी क्या है? RowNum BETWEEN 101 AND 200?
ypercube y

जवाबों:


1

यदि यह विशेष कार्य भार उस तालिका के विरुद्ध अधिकांश प्रश्नों का है जिस पर आप विचार कर सकते हैं:

ALTER TABLE Ticket ADD CONSTRAINT PK_Ticket PRIMARY KEY NONCLUSTERED (TicketId);

CREATE UNIQUE CLUSTERED INDEX IX_Ticket_Covering ON Ticket (
    InsertDateTime ASC
);

बातें:

  • क्या आप datetime2 (SQL 2008+; लचीली परिशुद्धता) का उपयोग कर सकते हैं
  • InsertDateTime आपकी परिशुद्धता के भीतर अद्वितीय होगा
  • यदि समय की कमी नहीं होती है तो अनोखा एसक्यूएल टाइप के छिपे हुए अनोखे कॉलम को जोड़ देगा। यह सभी गैर-अनुक्रमित सूचकांक में जोड़ा जाता है ताकि वे सही संकुल रिकॉर्ड का संदर्भ दे सकें

लाभ:

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

1

मैंने अतीत में इस तकनीक का उपयोग किया है। तालिका लगभग बड़ी नहीं थी, लेकिन खोज मापदंड अधिक जटिल था।

यह लघु संस्करण है।

CREATE PROC usp_Search
    (
    @StartDate  Date,
    @EndDate    Date,
    @Sites      Varchar(30) = NULL,
    @Assigned   Int = NULL, --Assuming only value possible
    @StartRow   Int,
    @EndRow     Int
    )
AS
DECLARE @TblSites   TABLE (ID Int)
IF @Sites IS NOT NULL
BEGIN
    -- Split @Sites into table @TblSites
END
SELECT  TicketId
FROM    (
        SELECT  TicketId,
                ROW_NUMBER() OVER(ORDER BY InsertDateTime DESC) as RowNum
        FROM    Ticket
                LEFT JOIN @TblSites
                    Ticket.SiteID = @TblSites.ID
        WHERE   InsertDateTime >= @StartDate 
                AND InsertDateTime < @EndDate
                AND (
                    @Assigned IS NULL 
                    OR AssignedId = @Assigned 
                    )
        ) _
WHERE   RowNum BETWEEN @StartRow AND @EndRow;

1

आपके पहले दो प्राथमिकताओं को देखते हुए मैं एक अनुक्रमित सूचकांक को देखूंगा InsertDateTime


0

आप विभाजन पर विचार क्यों नहीं करते? यह SQL 2008 में ऊपर की तरफ उपलब्ध है, लेकिन इसके लिए एंटरप्राइज़ संस्करण (या डेवलपर संस्करण) की आवश्यकता है।

मूल रूप से, आप अपनी तालिका को कई विभाजनों में विभाजित करते हैं और आप परिभाषित करते हैं कि आप विभाजन मानदंड (कार्य) क्या आप तिथि सीमा होंगे?

https://www.simple-talk.com/sql/database-administration/gail-shaws-sql-server-howlers/


-1

यदि क्लाइंट बार-बार उसी तरह से फ़िल्टर कर रहे हैं, तो आप उन प्रश्नों के लिए एक इंडेक्स बना सकते हैं।

जैसे ग्राहक SiteId और StatusId पर फ़िल्टर कर रहा है, आप एक अतिरिक्त सूचकांक बना सकते हैं:

CREATE NONCLUSTERED INDEX IX_Ticket_InsertDateTime_SiteId_StatusId ON Ticket     
(InsertDateTime DESC,
 SiteId [ASC/DESC],
 StatusId [ASC/DESC] ) 
 INCLUDE ( ... );

इस तरह, अधिकांश 'अधिक सामान्य' प्रश्न तेजी से चल सकते हैं।

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