Hindari kursor, kueri itu tidak membutuhkannya. SQL tidak bahasa imperatif (itulah sebabnya ia mendapat nama buruk karena semua orang menggunakannya sebagai satu ) - ini adalah bahasa yang ditetapkan.
Hal pertama yang dapat Anda lakukan adalah mempercepat eksekusi dasar SQL Anda, lebih sedikit waktu parsing/eksekusi kueri berarti lebih sedikit kemungkinan kebuntuan:
- Awal semua tabel Anda dengan
[dbo]
- ini memotong hingga 30% dari tahap penguraian. - Alias meja Anda - ini memotong sedikit dari tahap perencanaan.
- Mengutip pengenal mungkin mempercepat segalanya.
- Ini adalah tips dari mantan SQL-PM sebelum ada yang memutuskan untuk membantahnya.
Anda dapat menggunakan CTE untuk memperbarui data dan kemudian menggunakan UPDATE ... FROM ... SELECT
pernyataan untuk melakukan pembaruan yang sebenarnya. Ini akan lebih cepat daripada kursor, karena kursor anjing lambat bila dibandingkan dengan operasi set bersih (bahkan kursor 'selang kebakaran' tercepat seperti milik Anda). Lebih sedikit waktu yang dihabiskan untuk memperbarui berarti lebih sedikit kemungkinan kebuntuan. Catatan:Saya tidak memiliki tabel asli Anda, saya tidak dapat memvalidasi ini - jadi periksa dengan DB pengembangan.
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;
Selain itu, Anda dapat melarang penguncian PAGE pada indeks Anda, ini akan mengurangi kemungkinan beberapa baris mengunci seluruh halaman (karena eskalasi penguncian, hanya persentase tertentu dari baris yang perlu dikunci sebelum seluruh halaman dikunci).
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
Ini hanya akan mengurangi kemungkinan kebuntuan. Anda dapat mencoba membatasi @sekarang tanggal di masa lalu (yaitu today - 1 day
) untuk memastikan bahwa baris yang disisipkan tidak termasuk dalam predikat pembaruan; kemungkinan itu akan mencegah kebuntuan sepenuhnya.