Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

актуализирайте и вмъкнете заявки, създавайки задънена улица

Избягвайте курсорите, тази заявка нямаше нужда от тях. SQL не е императивен език (поради което получава лошо име, защото всички го използват като един ) - това е зададен език.

Първото нещо, което можете да направите, е да ускорите основното изпълнение на вашия SQL, по-малкото време за анализиране/изпълнение на заявката означава по-малък шанс за блокиране:

  • Префиксирайте всичките си таблици с [dbo] - това намалява до 30% от етапа на анализ.
  • Псевдоним на вашите маси - това отрязва малко количество от етапа на планиране.
  • Идентификаторите в кавички може ускорете нещата.
  • Това са съвети от бивш SQL-PM, преди някой да реши да го оспори.

Можете да използвате CTE, за да получите данните за актуализиране и след това да използвате UPDATE ... FROM ... SELECT изявление за извършване на действителните актуализации. Това ще бъде по-бързо от курсор, защото курсорите са кучешки бавни в сравнение с чистите операции (дори и най-бързият курсор „пожарен маркуч“ като вашия). По-малкото време, прекарано в актуализиране, означава по-малък шанс за блокиране. Забележка:Нямам вашите оригинални таблици, не мога да потвърдя това - така че го проверете в база данни за разработка.

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;

Освен това можете да забраните заключванията на PAGE във вашия индекс, това ще намали шансовете няколко реда да заключат цяла страница (поради ескалацията на заключването, само определен процент от редовете трябва да бъдат заключени, преди да бъде заключена цялата страница).

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

Това само ще намали шансовете за задънена улица. Може да опитате да ограничите @now до дата в миналото (т.е. today - 1 day ), за да се уверите, че вмъкнатият ред не попада в предиката за актуализиране; шансовете са, че ще предотврати напълно безизходицата.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. SQL:Как да запълня празни клетки със стойност на предишния ред?

  2. Заявка за получаване на имената на всички таблици в базата данни на SQL Server 2008

  3. намерете променлива дължина за sql сървър тип данни nvarchar от c# код

  4. Условно JOIN различни таблици

  5. Кога е по-добре да пишете ad hoc sql срещу съхранени процедури