IN () का उपयोग करके क्वेरी के प्रदर्शन में सुधार


14

मेरे पास निम्न SQL क्वेरी है:

SELECT
  Event.ID,
  Event.IATA,
  Device.Name,
  EventType.Description,
  Event.Data1,
  Event.Data2
  Event.PLCTimeStamp,
  Event.EventTypeID
FROM
  Event
INNER JOIN EventType ON EventType.ID = Event.EventTypeID
INNER JOIN Device ON Device.ID = Event.DeviceID
WHERE
  Event.EventTypeID IN (3, 30, 40, 41, 42, 46, 49, 50)
  AND Event.PLCTimeStamp BETWEEN '2011-01-28' AND '2011-01-29'
  AND Event.IATA LIKE '%0005836217%'
ORDER BY Event.ID;

मेरे पास Eventकॉलम के लिए टेबल पर एक इंडेक्स भी है TimeStamp। मेरी समझ यह है कि IN()बयान के कारण इस सूचकांक का उपयोग नहीं किया जाता है । तो मेरा सवाल है कि क्या IN()इस क्वेरी को गति देने के लिए इस विशेष विवरण के लिए एक इंडेक्स बनाने का कोई तरीका है ?

मैंने Event.EventTypeID IN (2, 5, 7, 8, 9, 14)सूचकांक पर फ़िल्टर के रूप में जोड़ने का भी प्रयास किया TimeStamp, लेकिन जब निष्पादन योजना को देखते हैं तो यह इस सूचकांक का उपयोग नहीं करता है। इस में किसी भी सुझाव या अंतर्दृष्टि बहुत सराहना की जाएगी।

नीचे चित्रमय योजना है:

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

और यहाँ .sqlplan फ़ाइल का लिंक दिया गया है


क्या हम निष्पादन योजना को भी देख सकते हैं? :)
डेज़ो

1
और कृपया .sqlplan एक्सटेंशन के साथ वास्तविक निष्पादन योजना (अनुमानित नहीं) पोस्ट करें। अधिकांश लोग केवल चित्रमय योजना का एक स्क्रीन शॉट पोस्ट करना चाहते हैं, और यह बहुत कम उपयोगी है।
हारून बर्ट्रेंड

ठीक है मैंने एक निष्पादन योजना और साथ ही SQL क्वेरी को अद्यतन किया।
सैंडर्सकेवाई

@SandersKY एक ही साइट पर प्रश्न से संबंधित सब कुछ रखने के लिए .sqlplan फ़ाइल को इनलाइन करना सबसे अच्छा है।
लॉजस्टोएल

1
@trygvis - अक्सर पदों पर लंबाई सीमाओं के कारण संभव नहीं होगा। शर्म की मुद्रा विनिमय आंतरिक रूप से पोस्ट अटैचमेंट की मेजबानी का समर्थन नहीं करता है।
मार्टिन स्मिथ

जवाबों:


18

निम्नलिखित सामान्य रूप की तालिकाएँ दी गई हैं:

CREATE TABLE Device 
(
    ID integer PRIMARY KEY
);

CREATE TABLE EventType
(
    ID integer PRIMARY KEY, 
    Name nvarchar(50) NOT NULL
);

CREATE TABLE [Event]
(
    ID integer PRIMARY KEY, 
    [TimeStamp] datetime NOT NULL, 
    EventTypeID integer NOT NULL REFERENCES EventType, 
    DeviceID integer NOT NULL REFERENCES Device
);

निम्नलिखित सूचकांक उपयोगी है:

CREATE INDEX f1 
ON [Event] ([TimeStamp], EventTypeID) 
INCLUDE (DeviceID)
WHERE EventTypeID IN (2, 5, 7, 8, 9, 14);

क्वेरी के लिए:

SELECT
  [Event].ID,
  [Event].[TimeStamp],
  EventType.Name,
  Device.ID
FROM
  [Event]
INNER JOIN EventType ON EventType.ID = [Event].EventTypeID
INNER JOIN Device ON Device.ID = [Event].DeviceID
WHERE
  [Event].[TimeStamp] BETWEEN '2011-01-28' AND '2011-01-29'
  AND Event.EventTypeID IN (2, 5, 7, 8, 9, 14);

फ़िल्टर ANDक्लॉज़ आवश्यकता को पूरा करता है , इंडेक्स की पहली कुंजी [TimeStamp]फ़िल्टर्ड के लिए एक खोज की अनुमति देता है EventTypeIDsऔर DeviceIDकॉलम सहित इंडेक्स को कवर करता है (क्योंकि तालिका DeviceIDमें शामिल होने के लिए आवश्यक है Device)।

योजना पूरी की

सूचकांक की दूसरी कुंजी - EventTypeIDसख्ती से आवश्यक नहीं है (यह एक INCLUDEdस्तंभ भी हो सकता है ); मैंने यहां बताए गए कारणों के लिए इसे कुंजी में शामिल किया है । सामान्य तौर पर, मैं लोगों को INCLUDEफ़िल्टर किए गए इंडेक्स WHEREक्लॉज़ से कम से कम कॉलम की सलाह देता हूं ।


प्रश्न में अद्यतन क्वेरी और निष्पादन योजना के आधार पर, मैं मानता हूं कि SSMS द्वारा सुझाए गए अधिक सामान्य सूचकांक की संभावना यहां बेहतर विकल्प है, जब तक कि फ़िल्टर्ड की सूची EventTypeIDsस्थिर नहीं होती है क्योंकि हारून भी अपने उत्तर में उल्लेख करता है:

CREATE TABLE Device 
(
    ID integer PRIMARY KEY,
    Name nvarchar(50) NOT NULL UNIQUE
);

CREATE TABLE EventType
(
    ID integer PRIMARY KEY, 
    Name nvarchar(20) NOT NULL UNIQUE,
    [Description] nvarchar(100) NOT NULL
);

CREATE TABLE [Event]
(
    ID integer PRIMARY KEY, 
    PLCTimeStamp datetime NOT NULL,
    EventTypeID integer NOT NULL REFERENCES EventType, 
    DeviceID integer NOT NULL REFERENCES Device,
    IATA varchar(50) NOT NULL,
    Data1 integer NULL,
    Data2 integer NULL,
);

सुझाया गया अनुक्रमणिका (यदि यह उपयुक्त है तो इसे अद्वितीय घोषित करें):

CREATE UNIQUE INDEX uq1
ON [Event]
    (EventTypeID, PLCTimeStamp)
INCLUDE 
    (DeviceID, IATA, Data1, Data2, ID);

निष्पादन योजना (अनियंत्रित वाक्यविन्यास, उत्पादन प्रणालियों में उपयोग न करें) से कार्डिनैलिटी जानकारी:

UPDATE STATISTICS dbo.Event WITH ROWCOUNT = 4042700, PAGECOUNT = 400000;
UPDATE STATISTICS dbo.EventType WITH ROWCOUNT = 22, PAGECOUNT = 1;
UPDATE STATISTICS dbo.Device WITH ROWCOUNT = 2806, PAGECOUNT = 28;

अद्यतित क्वेरी ( तालिका की INसूची दोहराते हुए EventTypeइस विशिष्ट मामले में ऑप्टिमाइज़र की मदद करता है):

SELECT
  Event.ID,
  Event.IATA,
  Device.Name,
  EventType.Description,
  Event.Data1,
  Event.Data2,
  Event.PLCTimeStamp,
  Event.EventTypeID
FROM
  Event
INNER JOIN EventType ON EventType.ID = Event.EventTypeID
INNER JOIN Device ON Device.ID = Event.DeviceID
WHERE
  Event.EventTypeID IN (3, 30, 40, 41, 42, 46, 49, 50)
  AND EventType.ID IN (3, 30, 40, 41, 42, 46, 49, 50)
  AND Event.PLCTimeStamp BETWEEN '2011-01-28' AND '2011-01-29'
  AND Event.IATA LIKE '%0005836217%'
ORDER BY Event.ID;

अनुमानित निष्पादन योजना:

दूसरी योजना

आपके द्वारा प्राप्त की जाने वाली योजना अलग-अलग होगी क्योंकि मैं अनुमानित आंकड़ों का उपयोग कर रहा हूं। सामान्य बिंदु यह है कि आप ऑप्टिमाइज़र को अधिक से अधिक जानकारी दे सकते हैं, और 4-मिलियन पंक्ति [Event]तालिका पर एक कुशल एक्सेस विधि (इंडेक्स) प्रदान कर सकते हैं ।


8

अधिकांश लागत क्लस्टर इंडेक्स स्कैन है, और जब तक यह तालिका वास्तव में विस्तृत नहीं होती है या आपको वास्तव में आउटपुट में उन सभी स्तंभों की आवश्यकता नहीं होती है, मेरा मानना ​​है कि SQL सर्वर का मानना ​​है कि यह वर्तमान परिदृश्य में इष्टतम पथ है जिसमें कुछ और नहीं बदला गया है । यह उन पंक्तियों की सीमा को कम करने के लिए एक रेंज स्कैन (एक CI की तलाश के रूप में लेबल) का उपयोग करता है जो इसमें रुचि रखता है, लेकिन आउटपुट के कारण इसे अभी भी आपके द्वारा बनाए गए फ़िल्टर किए गए इंडेक्स के साथ लुक या CI स्कैन की आवश्यकता होती है इस सीमा पर लक्षित है, और उस स्थिति में भी CI स्कैन शायद अभी भी सबसे सस्ता है (या कम से कम SQL सर्वर इसका अनुमान लगाता है)।

निष्पादन योजना आपको बताती है कि यह सूचकांक उपयोगी होगा:

CREATE NONCLUSTERED INDEX ix_EventTypeID_PLCTimeStamp_WithIncludes
  ON [dbo].[Event] ([EventTypeID],[PLCTimeStamp])
  INCLUDE ([ID],[DeviceID],[Data1],[Data2],[IATA]);

यद्यपि आपके डेटा तिरछा के आधार पर यह अन्य तरीके से बेहतर हो सकता है, जैसे:

CREATE NONCLUSTERED INDEX ix_PLCTimeStamp_EventTypeID_WithIncludes
  ON [dbo].[Event] ([PLCTimeStamp],[EventTypeID])
  INCLUDE ([ID],[DeviceID],[Data1],[Data2],[IATA]);

लेकिन मैं यह सुनिश्चित करने के लिए दोनों का परीक्षण करूंगा कि कौन सा बेहतर है, यदि या तो - उन दोनों अनुक्रमितों के बीच का अंतर और जो आपके पास अभी है वह केवल सीमांत हो सकता है (हमारे जानने के लिए बहुत से चर) और आपको ध्यान में रखना होगा कि एक अतिरिक्त सूचकांक को अतिरिक्त रखरखाव की आवश्यकता होती है, और यह आपके डीएमएल संचालन (सम्मिलित / अद्यतन / हटाएं) को विशेष रूप से प्रभावित कर सकता है। आप @SQLKiwi द्वारा सुझाए गए इस सूचकांक में फ़िल्टर मानदंड सहित विचार भी कर सकते हैं , लेकिन केवल तभी जब आप अक्सर खोज करने वाले EventTypeID मानों का सेट है। यदि वह सेट समय के साथ बदलता है, तो फ़िल्टर्ड इंडेक्स केवल इस विशिष्ट क्वेरी के लिए उपयोगी होगा।

इतनी कम पंक्ति गणना के साथ, मुझे आश्चर्य होता है कि वर्तमान में प्रदर्शन कितना खराब हो सकता है? यह क्वेरी 3 पंक्तियों को लौटाती है (लेकिन इसे कितनी पंक्तियों को अस्वीकार किया गया इसका कोई संकेत नहीं है)। तालिका में कितनी पंक्तियाँ हैं?


4

मुझे बस पता चलता है कि SQL Server 2008 R2 ने वास्तव में एक इंडेक्स सुझाव दिया था जब मैंने निष्पादन योजना चलाई थी। यह सुझाया गया सूचकांक क्वेरी को लगभग 90% तेज बनाता है।

यह सुझाव दिया सूचकांक निम्नलिखित था:

CREATE NONCLUSTERED INDEX [INDEX_spBagSearch] ON [dbo].[Event] 
(
    [EventTypeID] ASC,
    [PLCTimeStamp] ASC
)
INCLUDE ( [ID],
[DeviceID],
[Data1],
[Data2],
[IATA]) WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.