表上的新索引导致表经常被锁定

Gui*_*ipp 5 index sql-server entity-framework locking

这是我的表:

CREATE TABLE [dbo].[Trackers] (
    [IdTracker]             INT           IDENTITY (1, 1) NOT NULL,
    [IMEI]                  NVARCHAR (16) NULL,
    [CreationDate]          DATETIME      NULL,
    [SuppressionDate]       DATETIME      NULL,
    [LastUpdateDate]        DATETIME      NULL,
    [BuyDate]               DATETIME      NOT NULL,
    [Status]                INT           NOT NULL,
    [LastTrackerUpdateDate] DATETIME      NULL,
    [IdLastTrackerPosition] INT           NULL,
    PRIMARY KEY CLUSTERED ([IdTracker] ASC)
);


CREATE TABLE [dbo].[TrackerPositions] (
    [IdTrackerPosition] INT               IDENTITY (1, 1) NOT NULL,
    [TrackerId]         INT               NOT NULL,
    [Position]          [sys].[geography] NULL,
    [Date]              DATETIME          NOT NULL,
    [Speed]             REAL              NULL,
    [NbSatellites]      TINYINT           NULL,
    [Direction]         REAL              NULL,
    [HDOP]              REAL              NULL,
    PRIMARY KEY CLUSTERED ([IdTrackerPosition] ASC),
    CONSTRAINT [TrackerTrackerPosition] FOREIGN KEY ([TrackerId]) REFERENCES [dbo].     [Trackers] ([IdTracker])
 );
Run Code Online (Sandbox Code Playgroud)

跟踪器位置用于存储汽车跟踪器发送的位置。所以我有很多插入正在进行。而且我经常需要获得跟踪器已知的最后一个位置。

所以这是一个由 Entity Framework 生成的查询:

SELECT 
    [Limit1].[IdTrackerPosition] AS [IdTrackerPosition], 
    [Limit1].[TrackerId] AS [TrackerId], 
    [Limit1].[Position] AS [Position], 
    [Limit1].[Date] AS [Date], 
    [Limit1].[Speed] AS [Speed], 
    [Limit1].[NbSatellites] AS [NbSatellites], 
    [Limit1].[Direction] AS [Direction], 
    [Limit1].[HDOP] AS [HDOP]
    FROM   (SELECT DISTINCT 
        [Extent1].[TrackerId] AS [TrackerId]
        FROM [dbo].[TrackerPositions] AS [Extent1]
        WHERE ([Extent1].[Position] IS NOT NULL) AND ([Extent1].[TrackerId] IN (1, 48)) ) AS [Distinct1]
    OUTER APPLY  (SELECT TOP (1) [Project2].[IdTrackerPosition] AS [IdTrackerPosition], [Project2].[TrackerId] AS [TrackerId], [Project2].[Position] AS [Position], [Project2].[Date] AS [Date], [Project2].[Speed] AS [Speed], [Project2].[NbSatellites] AS [NbSatellites], [Project2].[Direction] AS [Direction], [Project2].[HDOP] AS [HDOP]
        FROM ( SELECT 
            [Extent2].[IdTrackerPosition] AS [IdTrackerPosition], 
            [Extent2].[TrackerId] AS [TrackerId], 
            [Extent2].[Position] AS [Position], 
            [Extent2].[Date] AS [Date], 
            [Extent2].[Speed] AS [Speed], 
            [Extent2].[NbSatellites] AS [NbSatellites], 
            [Extent2].[Direction] AS [Direction], 
            [Extent2].[HDOP] AS [HDOP]
            FROM [dbo].[TrackerPositions] AS [Extent2]
            WHERE ([Extent2].[Position] IS NOT NULL) AND ([Extent2].[TrackerId] IN (1, 48)) AND ([Distinct1].[TrackerId] = [Extent2].[TrackerId])
        )  AS [Project2]
        ORDER BY [Project2].[IdTrackerPosition] DESC ) AS [Limit1]
Run Code Online (Sandbox Code Playgroud)

这里是 SQL Server Studio 建议的索引:

CREATE NONCLUSTERED INDEX [_dta_index_TrackerPositions_5_352108395__K2_3] ON [dbo].[TrackerPositions]
(
    [TrackerId] ASC
)
INCLUDE (   [Position]) WITH (SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF) ON [PRIMARY]
Run Code Online (Sandbox Code Playgroud)

索引的性能要好得多,但我的大部分插入都被锁定了......

你们对我可以使用的更好的索引/选择有什么想法吗?

编辑:你们给我的索引在那之前很好。但是现在我的桌子更大了,我对性能有一些问题。

我试过这个查询,但结果更糟:

    SELECT 
        [IdTrackerPosition] AS [IdTrackerPosition], 
        [TrackerId] AS [TrackerId], 
        [Position] AS [Position], 
        [Date] AS [Date], 
        [Speed] AS [Speed], 
        [NbSatellites] AS [NbSatellites], 
        [Direction] AS [Direction], 
        [HDOP] AS [HDOP]
FROM
(
    SELECT 
        IdTrackerPosition,
        [TrackerId] AS [TrackerId], 
        [Position] AS [Position], 
        [Date] AS [Date], 
        [Speed] AS [Speed], 
        [NbSatellites] AS [NbSatellites], 
        [Direction] AS [Direction], 
        [HDOP] AS [HDOP],
        row_number() OVER (PARTITION BY TrackerId ORDER BY IdTrackerPosition DESC) AS rank_row
    FROM (
        SELECT
            IdTrackerPosition,
            [TrackerId] AS [TrackerId], 
            [Position] AS [Position], 
            [Date] AS [Date], 
            [Speed] AS [Speed], 
            [NbSatellites] AS [NbSatellites], 
            [Direction] AS [Direction], 
            [HDOP] AS [HDOP]
            FROM TrackerPositions tp
            WHERE tp.Position IS NOT null 
                AND [TrackerId] IN (9, 2, 24, 41, 10, 7, 1, 17, 16, 20, 3, 40, 13, 14, 18, 11, 12, 5, 6, 4, 8, 23, 19, 15, 42, 22, 39, 21, 33, 37, 38, 34, 26, 28, 36, 25, 29, 43, 27, 30, 35, 31, 32)               
        ) AS A
)  AS Z
WHERE rank_row <= 1
Run Code Online (Sandbox Code Playgroud)

谢谢 !

Pau*_*ite 3

更好的索引是(假设ORDER BY IdTrackerPosition DESC是正确的,并且查询不应指定ORDER BY [Date] DESC):

CREATE UNIQUE INDEX i -- Choose a better name!
ON dbo.TrackerPositions 
    (TrackerId, IdTrackerPosition DESC) 
INCLUDE 
    (Position, [Date], Speed, NbSatellites, Direction, HDOP);
Run Code Online (Sandbox Code Playgroud)

执行计划应该是这样的:

执行计划

如果Position IS NOT NULL谓词是频繁的,或者有合理的选择性,您可以将计算列添加到基表中,并将其包含在索引中 - 假设查询可以表示为引用计算列而不是Position IS NOT NULL明确地说:

-- Computed column
ALTER TABLE dbo.TrackerPositions
ADD PositionIsNull 
AS 
    CASE 
        WHEN Position IS NULL THEN CONVERT(bit, 1) 
        ELSE CONVERT(bit, 0) 
    END;

-- Modified index
CREATE UNIQUE INDEX i 
ON dbo.TrackerPositions 
    (TrackerId, PositionIsNull, IdTrackerPosition DESC) 
INCLUDE 
    (Position, [Date], Speed, NbSatellites, Direction, HDOP)
WITH (DROP_EXISTING = ON);
Run Code Online (Sandbox Code Playgroud)

修改后的查询:

SELECT 
    [Limit1].[IdTrackerPosition] AS [IdTrackerPosition], 
    [Limit1].[TrackerId] AS [TrackerId], 
    [Limit1].[Position] AS [Position], 
    [Limit1].[Date] AS [Date], 
    [Limit1].[Speed] AS [Speed], 
    [Limit1].[NbSatellites] AS [NbSatellites], 
    [Limit1].[Direction] AS [Direction], 
    [Limit1].[HDOP] AS [HDOP]
    FROM   
    (
        SELECT DISTINCT 
            [Extent1].[TrackerId] AS [TrackerId]
            FROM [dbo].[TrackerPositions] AS [Extent1]
            WHERE 
                Extent1.PositionIsNull = CONVERT(bit, 0)
                AND ([Extent1].[TrackerId] IN (1, 48)) 
    ) AS [Distinct1]
    OUTER APPLY  
    (SELECT TOP (1) 
        [Project2].[IdTrackerPosition] AS [IdTrackerPosition], 
        [Project2].[TrackerId] AS [TrackerId], 
        [Project2].[Position] AS [Position], 
        [Project2].[Date] AS [Date], 
        [Project2].[Speed] AS [Speed], 
        [Project2].[NbSatellites] AS [NbSatellites], 
        [Project2].[Direction] AS [Direction], 
        [Project2].[HDOP] AS [HDOP]
        FROM 
        ( 
            SELECT 
                [Extent2].[IdTrackerPosition] AS [IdTrackerPosition], 
                [Extent2].[TrackerId] AS [TrackerId], 
                [Extent2].[Position] AS [Position], 
                [Extent2].[Date] AS [Date], 
                [Extent2].[Speed] AS [Speed], 
                [Extent2].[NbSatellites] AS [NbSatellites], 
                [Extent2].[Direction] AS [Direction], 
                [Extent2].[HDOP] AS [HDOP]
            FROM [dbo].[TrackerPositions] AS [Extent2]
            WHERE 
                Extent2.PositionIsNull = CONVERT(bit, 0)
                AND ([Extent2].[TrackerId] IN (1, 48)) 
                AND ([Distinct1].[TrackerId] = [Extent2].[TrackerId])
        )  AS [Project2]
        ORDER BY 
            [Project2].[IdTrackerPosition] DESC 
    ) AS [Limit1]
Run Code Online (Sandbox Code Playgroud)

带有计算列的执行计划:

使用计算列进行计划