นี่คือการทำงานที่ลดลง: ฉันกำลังทำแบบสอบถามเลือก ทุกคอลัมน์ในWHERE
และส่วนORDER BY
คำสั่งจะอยู่ในดัชนีที่ไม่ใช่คลัสเตอร์IX_MachineryId_DateRecorded
เดียวซึ่งเป็นส่วนหนึ่งของคีย์หรือเป็นINCLUDE
คอลัมน์ ฉันกำลังเลือกคอลัมน์ทั้งหมดเพื่อที่จะส่งผลให้มีการค้นหาบุ๊กมาร์ก แต่ฉันกำลังทำอยู่TOP (1)
ดังนั้นเซิร์ฟเวอร์จึงสามารถบอกได้ว่าการค้นหาจำเป็นต้องทำเพียงครั้งเดียวในตอนท้าย
สิ่งสำคัญที่สุดคือเมื่อฉันบังคับให้แบบสอบถามใช้ดัชนีIX_MachineryId_DateRecorded
มันจะทำงานในเวลาน้อยกว่าหนึ่งวินาที ถ้าฉันปล่อยให้เซิร์ฟเวอร์ตัดสินใจว่าจะใช้ดัชนีใดมันจะเลือกIX_MachineryId
และใช้เวลาประมาณหนึ่งนาที ที่แนะนำให้ฉันจริง ๆ ว่าฉันได้ทำดัชนีถูกต้องและเซิร์ฟเวอร์เพิ่งตัดสินใจไม่ถูกต้อง ทำไม?
CREATE TABLE [dbo].[MachineryReading] (
[Id] INT IDENTITY (1, 1) NOT NULL,
[Location] [sys].[geometry] NULL,
[Latitude] FLOAT (53) NOT NULL,
[Longitude] FLOAT (53) NOT NULL,
[Altitude] FLOAT (53) NULL,
[Odometer] INT NULL,
[Speed] FLOAT (53) NULL,
[BatteryLevel] INT NULL,
[PinFlags] BIGINT NOT NULL,
[DateRecorded] DATETIME NOT NULL,
[DateReceived] DATETIME NOT NULL,
[Satellites] INT NOT NULL,
[HDOP] FLOAT (53) NOT NULL,
[MachineryId] INT NOT NULL,
[TrackerId] INT NOT NULL,
[ReportType] NVARCHAR (1) NULL,
[FixStatus] INT DEFAULT ((0)) NOT NULL,
[AlarmStatus] INT DEFAULT ((0)) NOT NULL,
[OperationalSeconds] INT DEFAULT ((0)) NOT NULL,
CONSTRAINT [PK_dbo.MachineryReading] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_dbo.MachineryReading_dbo.Machinery_MachineryId] FOREIGN KEY ([MachineryId]) REFERENCES [dbo].[Machinery] ([Id]) ON DELETE CASCADE,
CONSTRAINT [FK_dbo.MachineryReading_dbo.Tracker_TrackerId] FOREIGN KEY ([TrackerId]) REFERENCES [dbo].[Tracker] ([Id]) ON DELETE CASCADE
);
GO
CREATE NONCLUSTERED INDEX [IX_MachineryId]
ON [dbo].[MachineryReading]([MachineryId] ASC);
GO
CREATE NONCLUSTERED INDEX [IX_TrackerId]
ON [dbo].[MachineryReading]([TrackerId] ASC);
GO
CREATE NONCLUSTERED INDEX [IX_MachineryId_DateRecorded]
ON [dbo].[MachineryReading]([MachineryId] ASC, [DateRecorded] ASC)
INCLUDE([OperationalSeconds], [FixStatus]);
ตารางถูกแบ่งเป็นช่วงเดือน (แต่ฉันยังไม่เข้าใจว่าเกิดอะไรขึ้นที่นั่น)
ALTER PARTITION SCHEME PartitionSchemeMonthRange NEXT USED [Primary]
ALTER PARTITION FUNCTION [PartitionFunctionMonthRange]() SPLIT RANGE(N'2016-01-01T00:00:00.000')
ALTER PARTITION SCHEME PartitionSchemeMonthRange NEXT USED [Primary]
ALTER PARTITION FUNCTION [PartitionFunctionMonthRange]() SPLIT RANGE(N'2016-02-01T00:00:00.000')
...
CREATE UNIQUE CLUSTERED INDEX [PK_dbo.MachineryReadingPs] ON MachineryReading(DateRecorded, Id) ON PartitionSchemeMonthRange(DateRecorded)
แบบสอบถามที่ฉันจะเรียกใช้ตามปกติ:
SELECT TOP (1) [Id], [Location], [Latitude], [Longitude], [Altitude], [Odometer], [ReportType], [FixStatus], [AlarmStatus], [Speed], [BatteryLevel], [PinFlags], [DateRecorded], [DateReceived], [Satellites], [HDOP], [OperationalSeconds], [MachineryId], [TrackerId]
FROM [dbo].[MachineryReading]
--WITH(INDEX(IX_MachineryId_DateRecorded)) --This makes all the difference
WHERE ([MachineryId] = @p__linq__0) AND ([DateRecorded] >= @p__linq__1) AND ([DateRecorded] < @p__linq__2) AND ([OperationalSeconds] > 0)
ORDER BY [DateRecorded] ASC
แผนคำถาม: https://www.brentozar.com/pastetheplan/?id=r1c-RpxNx
แผนการสืบค้นพร้อมดัชนีบังคับ: https://www.brentozar.com/pastetheplan/?id=SywwTagVe
แผนรวมเป็นแผนปฏิบัติการจริง แต่ในฐานข้อมูลการจัดเตรียม (ประมาณ 1/100 ของขนาดสด) ฉันลังเลที่จะเล่นซอกับฐานข้อมูลสดเพราะฉันเพิ่งเริ่มต้นที่ บริษัท นี้ประมาณหนึ่งเดือนที่ผ่านมา
ฉันรู้สึกว่ามันเกิดจากการแบ่งพาร์ติชันและโดยทั่วไปคิวรีของฉันจะครอบคลุมทุกพาร์ติชันเดียว (เช่นเมื่อฉันต้องการบันทึกครั้งแรกหรือครั้งสุดท้ายที่OperationalSeconds
เคยบันทึกไว้สำหรับหนึ่งเครื่อง) อย่างไรก็ตามข้อความค้นหาที่ฉันเขียนด้วยมือทั้งหมดนั้นทำงานได้เร็วกว่าสิ่งที่EntityFrameworkสร้าง10 - 100 เท่าดังนั้นฉันเพิ่งจะทำขั้นตอนการจัดเก็บ