总结:我正在执行选择查询。WHERE
and ORDER BY
子句中的每一列都在单个非聚集索引中IX_MachineryId_DateRecorded
,可以作为键的一部分,也可以作为INCLUDE
列。我选择了所有列,因此将导致书签查找,但我只是在考虑TOP (1)
,因此可以肯定的是服务器可以告诉查找,最后只需要执行一次。
最重要的是,当我强制查询使用index时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倍,因此,我将创建一个存储过程。