Undvik markörer, den frågan behövde dem inte. SQL är inte ett imperativt språk (det är därför det får ett dåligt namn eftersom alla använder det som ett ) - det är ett fastställt språk.
Det första du kan göra är att påskynda den grundläggande exekveringen av din SQL, mindre tid att analysera/köra frågan betyder mindre risk för ett dödläge:
- Prefix alla dina tabeller med
[dbo]
- detta minskar upp till 30 % rabatt på analysstadiet. - Alias dina tabeller – det skär av en liten summa från planeringsstadiet.
- Citatidentifierare kan skynda på saker och ting.
- Det här är tips från en före detta SQL-PM innan någon bestämmer sig för att bestrida det.
Du kan använda en CTE för att få data att uppdatera och sedan använda en UPDATE ... FROM ... SELECT
uttalande för att göra de faktiska uppdateringarna. Detta kommer att vara snabbare än en markör, eftersom markörer är hund långsamma jämfört med rena inställningar (även den snabbaste "brandslang"-markören som din). Mindre tid som läggs på uppdatering betyder mindre risk för ett dödläge. Obs:Jag har inte dina ursprungliga tabeller, jag kan inte validera detta - så kontrollera det mot en utvecklings-DB.
DECLARE @nowTime datetime = convert(datetime, @now, 21);
WITH [DailyAggregates] AS
(
SELECT
[D].[dailyId] AS [dailyId],
[D].[spentDaily] AS [spentDaily],
[D].[impressionsCountCache] AS [impressionsCountCache],
SUM([I].[amountCharged]) as [sumCharged],
COUNT([I].[impressionId]) as [countImpressions]
FROM [dbo].[Daily] AS [D]
INNER JOIN [dbo].[Impressions] AS [I]
ON [I].[dailyId] = [D].[dailyId]
WHERE [I].[isCharged] = 0
AND [I].[showTime] < @nowTime
AND [D].[isActive] = 1
GROUP BY [D].[dailyId], [D].[spentDaily], [D].[impressionsCountCache]
)
UPDATE [dbo].[Daily]
SET [spentDaily] = [A].[spentDaily] + [A].[sumCharged],
[impressionsCountCache] = [A].[impressonsCountCache] + [A].[countImpressions]
FROM [Daily] AS [D]
INNER JOIN [DailyAggregates] AS [A]
ON [D].[dailyId] = [A].[dailyId];
UPDATE [dbo].[Impressions]
SET [isCharged] = 1
WHERE [showTime] < @nowTime
AND [isCharged] = 0;
Dessutom kan du inte tillåta PAGE-lås på ditt index, detta kommer att minska chansen att några rader låser en hel sida (på grund av låsning av eskalering behöver bara en viss procentandel av raderna låsas innan hela sidan bara låses).
CREATE NONCLUSTERED INDEX [IDX_Impressions_isCharged_showTime] ON [dbo].[Impressions]
(
[showTime] ASC, -- I have a hunch that switching these around might have an effect.
[isCharged] ASC
)
WITH (ALLOW_PAGE_LOCKS = OFF)
ON [PRIMARY]
GO
Detta kommer bara att minska risken för ett dödläge. Du kan försöka begränsa @nu ett datum i det förflutna (dvs. today - 1 day
) för att se till att den infogade raden inte hamnar i uppdateringspredikatet; chansen är stor att det kommer att förhindra dödläget helt.