Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

aktualizuj i wstawiaj zapytania tworząc impas

Unikaj kursorów, to zapytanie ich nie potrzebowało. SQL nie język imperatywny (dlatego zyskuje złą sławę, ponieważ wszyscy używają go jako jednego ) - to ustawiony język.

Pierwszą rzeczą, którą możesz zrobić, to przyspieszyć podstawowe wykonanie twojego SQL, mniej czasu na analizowanie/wykonywanie zapytania oznacza mniejszą szansę na zakleszczenie:

  • Poprzedź wszystkie tabele przedrostkiem [dbo] - zmniejsza to do 30% etapu analizy.
  • Zamień swoje tabele – odcina niewielką ilość od etapu planowania.
  • Cytowanie identyfikatorów może przyspieszyć działanie.
  • Są to wskazówki od ex-SQL-PM, zanim ktokolwiek zdecyduje się je zakwestionować.

Możesz użyć CTE, aby pobrać dane do aktualizacji, a następnie użyć UPDATE ... FROM ... SELECT oświadczenie, aby dokonać rzeczywistych aktualizacji. Będzie to szybsze niż kursor, ponieważ kursory są wolne przez psa w porównaniu do czystych operacji ustawiania (nawet najszybszy kursor „węża strażackiego”, taki jak twój). Mniej czasu spędzonego na aktualizowaniu oznacza mniejszą szansę na zakleszczenie. Uwaga:nie mam twoich oryginalnych tabel, nie mogę tego zweryfikować - więc sprawdź to z rozwojową bazą danych.

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;

Co więcej, możesz zabronić blokowania PAGE w swoim indeksie, zmniejszy to szanse na zablokowanie całej strony przez kilka wierszy (ze względu na blokowanie eskalacji tylko pewien procent wierszy musi zostać zablokowany, zanim cała strona zostanie po prostu zablokowana).

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

To tylko zmniejszy szanse na impas. Możesz spróbować ograniczyć @now datę z przeszłości (np. today - 1 day ), aby upewnić się, że wstawiony wiersz nie należy do predykatu aktualizacji; są szanse, że całkowicie zapobiegnie impasowi.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Powiadomienia o zapytaniach SQL Server w JAVA

  2. Jak zaktualizować dane z datatable do tabeli sql?

  3. Jak znaleźć wszystkie nazwy kolumn synonimu?

  4. SQL Server IN a wydajność EXISTS

  5. Uzyskiwanie przesunięcia przesunięcia daty i czasu w SQL Server