ปรับปรุงประสิทธิภาพของการสืบค้นโดยใช้ 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


เราสามารถดูแผนปฏิบัติการได้หรือไม่ :)
dezso

1
และโปรดโพสต์แผนการดำเนินการตามจริง (ไม่ประมาณ) ด้วยส่วนขยาย. sqlplan คนส่วนใหญ่ต้องการโพสต์ภาพหน้าจอของแผนกราฟิกและนั่นมีประโยชน์น้อยกว่ามาก
Aaron Bertrand

ตกลงฉันได้เพิ่มแผนการดำเนินการเช่นเดียวกับการปรับปรุงแบบสอบถาม SQL
SandersKY

@SandersKY ที่ดีที่สุดคือ inline ไฟล์. sqlplan เพื่อให้ทุกอย่างที่เกี่ยวข้องกับคำถามในเว็บไซต์เดียวกัน
Trygve Laugstøl

1
@trygvis - บ่อยครั้งที่เป็นไปไม่ได้เนื่องจากข้อจำกัดความยาวของโพสต์ Shame stack exchange ไม่รองรับการโฮสต์ไฟล์แนบภายใน
Martin Smith

คำตอบ:


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 Server เป็นเส้นทางที่ดีที่สุดในสถานการณ์ปัจจุบันโดยไม่มีอะไรเปลี่ยนแปลง . มันใช้การสแกนแบบช่วง (ระบุว่าเป็นการค้นหาแบบ CI) เพื่อ จำกัด ช่วงของแถวที่สนใจ แต่เนื่องจากผลลัพธ์มันจะยังคงต้องการการค้นหาหรือการสแกนแบบ CI แม้จะมีดัชนีที่กรองที่คุณสร้างขึ้น มีการกำหนดเป้าหมายในช่วงนี้และแม้กระทั่งในกรณีนั้นการสแกน CI อาจยังคงถูกที่สุด

แผนการดำเนินการไม่ได้บอกคุณว่าดัชนีนี้จะเป็นประโยชน์:

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]);

แต่ฉันจะทดสอบทั้งสองอย่างเพื่อให้แน่ใจว่าสิ่งใดดีกว่าถ้าอย่างใดอย่างหนึ่ง - ความแตกต่างระหว่างดัชนีเหล่านี้กับสิ่งที่คุณมีตอนนี้อาจเป็นเพียงเล็กน้อย (ตัวแปรมากเกินไปที่เราจะรู้) และคุณต้องคำนึงว่า ดัชนีต้องการการบำรุงรักษาพิเศษและสิ่งนี้สามารถส่งผลกระทบต่อการดำเนินงาน DML ของคุณ (แทรก / อัปเดต / ลบ) คุณอาจพิจารณารวมถึงเกณฑ์การกรองในดัชนีนี้ตามที่แนะนำโดย @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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.