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

Изпълнение на големи заявки във фонов режим MS SQL

От моя гледна точка вашият сървър има сериозен проблем с производителността. Дори ако приемем, че нито един от записите в заявката

select some_col with (nolock) where id_col between 57000000 and 57001000

беше в паметта, не би трябвало да отнеме 21 секунди, за да прочете няколкото страници последователно от диска (вашият клъстерен индекс на id_col не трябва да бъде фрагментиран, ако е автоматична идентичност и не сте направили нещо глупаво като добавяне на „desc“ към дефиницията на индекса).

Но ако не можете/няма да поправите това, моят съвет е да направите актуализацията в малки пакети като 100-1000 записа наведнъж (в зависимост от това колко време отнема функцията за търсене). Една актуализация/транзакция не трябва да отнема повече от 30 секунди.

Виждате, че всяка актуализация запазва изключително заключване на всички записи, които е променила, докато транзакцията приключи. Ако не използвате изрична транзакция, всеки оператор се изпълнява в единичен автоматичен контекст на транзакция, така че заключванията се освобождават, когато операторът за актуализиране е готов.

Но все още можете да попаднете в задънени блокировки по този начин, в зависимост от това какво правят другите процеси. Ако те модифицират повече от един запис наведнъж или дори ако съберат и задържат брави за четене на няколко реда, можете да получите задънени блокировки.

За да избегнете задънените блокировки, вашето изявление за актуализиране трябва да заключи всички записи, които ще модифицира наведнъж. Начинът да направите това е да поставите единичния израз за актуализиране (само с няколко реда, ограничени от id_col) в транзакция с възможност за сериализиране като

IF @@TRANCOUNT > 0
  -- Error: You are in a transaction context already

SET NOCOUNT ON
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

-- Insert Loop here to work "x" through the id range
  BEGIN TRANSACTION
    UPDATE SOMETABLE
      SET [some_col] = dbo.ufn_SomeFunction(CONVERT(NVARCHAR(500), another_column))
      WHERE [some_col] = 243 AND id_col BETWEEN x AND x+500 -- or whatever keeps the update in the small timerange
  COMMIT
-- Next loop

-- Get all new records while you where running the loop. If these are too many you may have to paginate this also:
BEGIN TRANSACTION
  UPDATE SOMETABLE
    SET [some_col] = dbo.ufn_SomeFunction(CONVERT(NVARCHAR(500), another_column))
    WHERE [some_col] = 243 AND id_col >= x
COMMIT

За всяка актуализация това ще отнеме актуализация/изключително заключване на ключов диапазон на дадените записи (но само тях, защото ограничавате актуализацията чрез ключа на клъстерния индекс). Той ще изчака всички други актуализации на същите записи да завършат, след което ще получи заключването си (предизвиквайки блокиране за всички други транзакции, но все още само за дадените записи), след това ще актуализира записите и ще освободи заключването.

Последният допълнителен оператор е важен, защото ще отнеме заключване на ключов диапазон до „безкрайност“ и по този начин ще предотврати дори вмъквания в края на диапазона, докато се изпълнява операторът за актуализиране.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. TSQL For Filter Experice From Range множествен избор

  2. Разлика между дата и час в sqlserver?

  3. COT() Примери в SQL Server

  4. Как да намерите съпоставянето в SQL Server (T-SQL)

  5. Как да преминавам само през файлове, които не съществуват в дестинацията, използвайки SSIS пакет?