Undgå markører, den forespørgsel havde ikke brug for dem. SQL er ikke et imperativt sprog (hvorfor det får et dårligt navn, fordi alle bruger det som ét ) - det er et fast sprog.
Den første ting du kan gøre er at fremskynde den grundlæggende udførelse af din SQL, mindre tid på at parse/udføre forespørgslen betyder mindre chance for en dødvande:
- Prefiks alle dine tabeller med
[dbo]
- dette skærer op til 30 % i rabat på parsestadiet. - Alias dine tabeller - det afskærer en lille mængde fra planlægningsstadiet.
- Citere-id'er kan fremskynde tingene.
- Dette er tips fra en tidligere SQL-PM, før nogen beslutter sig for at bestride det.
Du kan bruge en CTE til at få dataene til at opdatere og derefter bruge en UPDATE ... FROM ... SELECT
erklæring for at foretage de faktiske opdateringer. Dette vil være hurtigere end en markør, fordi markører er hund langsom sammenlignet med rent sæt operationer (selv den hurtigste 'brandslange'-markør som din). Mindre tid brugt på at opdatere betyder mindre chance for en dødvande. Bemærk:Jeg har ikke dine originale tabeller, jeg kan ikke validere dette - så tjek det mod en udviklings-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;
Desuden kan du forbyde PAGE-låse på dit indeks, dette vil mindske chancerne for, at nogle få rækker låser en hel side (på grund af låseeskalering skal kun en vis procentdel af rækker låses, før hele siden lige er låst).
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
Dette vil blot mindske chancerne for en dødvande. Du kan prøve at begrænse @nu til en dato i fortiden (dvs. today - 1 day
) for at sikre, at den indsatte række ikke falder ind under opdateringsprædikatet; chancerne er, at det vil forhindre dødvandet helt.