sql >> Base de Datos >  >> RDS >> Sqlserver

actualizar e insertar consultas creando un interbloqueo

Evite los cursores, esa consulta no los necesitaba. SQL no un lenguaje imperativo (razón por la cual tiene mala fama porque todo el mundo lo usa como tal ) - es un idioma establecido.

Lo primero que puede hacer es acelerar la ejecución básica de su SQL, menos tiempo analizando/ejecutando la consulta significa menos posibilidades de un punto muerto:

  • Prefije todas sus tablas con [dbo] - esto reduce hasta un 30 % de la etapa de análisis.
  • Alias ​​tus tablas:corta una pequeña cantidad de la etapa de planificación.
  • Citar identificadores puede acelerar las cosas.
  • Estos son consejos de un ex-SQL-PM antes de que alguien decida disputarlo.

Puede usar un CTE para actualizar los datos y luego usar UPDATE ... FROM ... SELECT declaración para hacer las actualizaciones reales. Esto será más rápido que un cursor, porque los cursores son perros lentos en comparación con las operaciones de conjunto limpio (incluso el cursor de 'manguera de incendios' más rápido como el suyo). Menos tiempo dedicado a la actualización significa menos posibilidades de un punto muerto. Nota:no tengo sus tablas originales, no puedo validar esto, así que verifíquelo con una base de datos de desarrollo.

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;

Además, podría deshabilitar los bloqueos de PÁGINA en su índice, esto disminuirá las posibilidades de que algunas filas bloqueen una página completa (debido a la escalada de bloqueo, solo es necesario bloquear un cierto porcentaje de filas antes de que se bloquee toda la página).

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

Esto solo mitigará las posibilidades de un punto muerto. Puede intentar restringir @ahora una fecha en el pasado (es decir, today - 1 day ) para asegurarse de que la fila insertada no caiga en el predicado de actualización; es probable que prevenga el interbloqueo por completo.