Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

atualizar e inserir consultas criando um impasse


Evite cursores, essa consulta não precisava deles. SQL não uma linguagem imperativa (é por isso que tem um nome ruim porque todos a usam como uma ) - é um idioma definido.

A primeira coisa que você pode fazer é acelerar a execução básica do seu SQL, menos tempo analisando/executando a consulta significa menos chance de um impasse:
  • Prefixe todas as suas tabelas com [dbo] - isso reduz até 30% no estágio de análise.
  • Alias ​​suas tabelas - ele corta uma pequena quantidade do estágio de planejamento.
  • Citar identificadores pode acelerar as coisas.
  • Estas são dicas de um ex-SQL-PM antes que alguém decida contestá-las.

Você pode usar um CTE para atualizar os dados e, em seguida, usar um UPDATE ... FROM ... SELECT instrução para fazer as atualizações reais. Isso será mais rápido que um cursor, porque os cursores são lentos quando comparado a operações de conjunto limpo (mesmo o cursor de 'mangueira de incêndio' mais rápido como o seu). Menos tempo gasto na atualização significa menos chance de um impasse. Observação:não tenho suas tabelas originais, não posso validar isso - então verifique com um banco de dados de desenvolvimento.
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;

Além disso, você pode não permitir bloqueios de PAGE em seu índice, isso diminuirá as chances de algumas linhas bloquearem uma página inteira (devido ao escalonamento de bloqueio, apenas uma certa porcentagem de linhas precisa ser bloqueada antes que a página inteira seja bloqueada).
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

Isso apenas mitigará as chances de um impasse. Você pode tentar restringir @agora uma data no passado (ou seja, today - 1 day ) para garantir que a linha inserida não caia no predicado de atualização; as chances são de que isso evitará o impasse completamente.