I have a table for statistic values, it holds millions of records, which is defined like this:
CREATE TABLE [dbo].[Statistic]
(
[Id] [INT] IDENTITY(1, 1) NOT NULL
, [EntityId] [INT] NULL
, [EntityTypeId] [UNIQUEIDENTIFIER] NOT NULL
, [ValueTypeId] [UNIQUEIDENTIFIER] NOT NULL
, [Value] [DECIMAL](19, 5) NOT NULL
, [Date] [DATETIME2](7) NULL
, [AggregateTypeId] [INT] NOT NULL
, [JsonData] [NVARCHAR](MAX) NULL
, [WeekDay] AS (DATEDIFF(DAY, CONVERT([DATETIME], '19000101', (112)), [Date]) % (7) + (1)) PERSISTED
, CONSTRAINT [PK_Statistic]
PRIMARY KEY NONCLUSTERED ([Id] ASC)
);
CREATE UNIQUE CLUSTERED INDEX [IX_Statistic_EntityId_EntityTypeId_ValueTypeId_AggregateTypeId_Date]
ON [dbo].[Statistic] (
[EntityId] ASC
, [EntityTypeId] ASC
, [ValueTypeId] ASC
, [AggregateTypeId] ASC
, [Date] ASC
);
CREATE NONCLUSTERED INDEX [IX_Date] ON [dbo].[Statistic] ([Date] ASC);
CREATE NONCLUSTERED INDEX [IX_EntityId]
ON [dbo].[Statistic] ([EntityId] ASC)
INCLUDE ([Id]);
CREATE NONCLUSTERED INDEX [IX_EntityType_Agg_Date]
ON [dbo].[Statistic] ([EntityTypeId] ASC, [AggregateTypeId] ASC, [Date] ASC)
INCLUDE ([Id], [EntityId], [ValueTypeId]);
CREATE NONCLUSTERED INDEX [IX_Statistic_ValueTypeId]
ON [dbo].[Statistic] ([ValueTypeId] ASC)
INCLUDE ([Id]);
CREATE NONCLUSTERED INDEX [IX_WeekDay]
ON [dbo].[Statistic] ([AggregateTypeId] ASC, [WeekDay] ASC, [Date] ASC)
INCLUDE ([Id]);
ALTER TABLE [dbo].[Statistic]
ADD CONSTRAINT [PK_Statistic]
PRIMARY KEY NONCLUSTERED ([Id] ASC);
During updates with merge, sql server locks the whole table instead of pages/rows, @inTbl
is a key/value datatable passed as parameter
MERGE INTO Statistic AS stat
USING
(SELECT inTbl.EntityId, inTbl.Value FROM @p0 AS inTbl) AS src
ON src.EntityId = stat.EntityId
AND stat.EntityTypeId = @p1
AND stat.ValueTypeId = @p2
AND stat.Date IS NULL
AND stat.AggregateTypeId = @p3
WHEN MATCHED THEN
UPDATE SET stat.Value = src.value
WHEN NOT MATCHED BY TARGET THEN
INSERT (EntityTypeId, ValueTypeId, Date, AggregateTypeId, EntityId, Value)
VALUES
(@p4, @p5, @p6, @p7, src.entityId, src.value);
So, I have 2 problems: 1) the merge sometimes takes forever to finish
2) updates like this wait for merge to finish:
UPDATE [dbo].[Statistic]
SET [Value] = @p0, [JsonData] = @p1
WHERE [EntityTypeId] = @p2
AND [ValueTypeId] = @p3
AND [Date] = @p4
AND [EntityId] = @p5
AND [AggregateTypeId] = @p6;
I have plans/locks files for the queries, but they are rather big, so here they are
before index rebuid: https://www.brentozar.com/pastetheplan/?id=S19EgxYIB
after index rebuild: https://www.brentozar.com/pastetheplan/?id=SyjexxtLH
What can be the problem? This happens occasionally and may sometimes go away after clustered index rebuild.
The clustered index goes fragmeted to 90+% in a day or so. How can I prevent this fragmentation?