sql >> Database teknologi >  >> RDS >> Sqlserver

opdater og indsæt forespørgsler og skaber et dødvande

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.



  1. Overtrædelse af UNIQUE KEY-begrænsning på INSERT WHERE COUNT(*) =0 på SQL Server 2005

  2. Hvordan afrundes til nærmeste X minutter med PL/pgSQL?

  3. Sådan får du et OBJECT_NAME() fra en anden database i SQL Server

  4. Mysql Opret database med specialtegn i navnet