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

Анатомията на задръстванията на SQL Server и най-добрите начини за избягването им

Специалистите по бази данни рутинно се сблъскват с проблеми с производителността на базата данни като неправилно индексиране и лошо написан код в производствените SQL екземпляри. Да предположим, че сте актуализирали транзакция и SQL Server съобщи следното съобщение за блокиране. За DBA, които тепърва започват, това може да бъде шок.

В тази статия ще разгледаме задънките на SQL Server и най-добрите начини да ги избегнем.

Какво е блокиране на SQL Server?

SQL Server е много транзакционна база данни. Например, да предположим, че поддържате базата данни за портал за онлайн пазаруване, където получавате нови поръчки от клиенти денонощно. Множество потребители вероятно извършват една и съща дейност по едно и също време. В този случай вашата база данни трябва да следва свойствата за атомарност, последователност, изолация, издръжливост (ACID), за да бъде последователна, надеждна и да защити целостта на данните.

Изображението по-долу описва свойствата на ACID в релационна база данни.

За да следва свойствата на ACID, SQL Server използва заключващи механизми, ограничения и записване напред. Различните типове заключване включват:изключителна ключалка(X), споделена ключалка(S), заключване за актуализиране (U), заключване на намерение (I), заключване на схема (SCH) и заключване за групово актуализиране (BU). Тези ключалки могат да бъдат придобити на ниво ключ, таблица, ред, страница и база данни.

Да предположим, че имате двама потребители, John и Peter, които са свързани към клиентската база данни.

  • Джон иска да актуализира записите за клиента, който има [customerid] 1.
  • В същото време Питър иска да извлече стойността за клиента, който има [customerid] 1.

В този случай SQL Server използва следните ключалки както за Джон, така и за Питър.

Ключи за Джон

  • Необходимо е изключително заключване (IX) на клиентската таблица и страницата, която съдържа записа.
  • Допълнително е необходимо изключително заключване (X) на реда, който Джон иска да актуализира. Той не позволява на всеки друг потребител да променя данните на реда, докато процес А не освободи заключването си.

Ключи за Петър

  • Той придобива заключване за споделено намерение (IS) на таблицата с клиенти и страницата, която съдържа записа съгласно клаузата where.
  • Опитва се да вземе споделено заключване, за да прочете реда. Този ред вече има изключително заключване за Джон.

В този случай Питър трябва да изчака, докато Джон приключи работата си и освободи изключителната ключалка. Тази ситуация е известна като блокиране.

Да предположим, че в друг сценарий Джон и Петър имат следните ключалки.

  • Джон има ексклузивно заключване на клиентската маса за идентификатор на клиента 1.
  • Peter има ексклузивно заключване на таблицата за поръчки за идентификатор на клиента 1.
  • Джон изисква изключително заключване на таблицата с поръчки, за да завърши транзакцията си. Питър вече има изключителна ключалка на масата за поръчки.
  • Питър изисква изключително заключване на клиентската маса, за да завърши транзакцията си. Джон вече има изключителна ключалка на масата на клиента.

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

Механизми за наблюдение на блокиране на SQL Server

SQL Server периодично наблюдава ситуациите в застой, като използва нишката за наблюдение на застой. Това проверява процесите, включени в задънена улица, и идентифицира дали дадена сесия е станала жертва на задънена улица. Той използва вътрешен механизъм за идентифициране на процеса на жертва на безизходица. По подразбиране транзакцията с най-малко ресурси, необходими за връщане назад, се счита за жертва.

SQL Server убива сесията жертва, за да може друга сесия да придобие необходимото заключване, за да завърши транзакцията си. По подразбиране SQL Server проверява ситуацията в застой на всеки 5 секунди, използвайки монитора за блокиране. Ако открие блокиране, може да намали честотата от 5 секунди до 100 милисекунди в зависимост от възникването на задънена улица. Той отново нулира нишката за наблюдение на 5 секунди, ако не се появяват чести блокирания.

След като SQL Server убие процес като жертва на безизходица, ще получите следното съобщение. В тази сесия процес ID 69 беше жертва на безизходица.

Въздействието от използването на изрази за приоритет за блокиране на SQL Server

По подразбиране SQL Server маркира транзакцията с най-евтиното връщане като жертва в безизходица. Потребителите могат да задават приоритет на блокиране в транзакция, като използват израза DEADLOCK_PRIORITY.

SET DEADLOCK_PRIORITY

Той използва следните аргументи:

  • Нисък:Еквивалентен е на приоритет в застой -5
  • Нормално:Това е приоритетът по подразбиране 0 за блокиране
  • Висок:Това е най-високият приоритет 5.

Можем също да зададем числови стойности за приоритет на блокиране от -10 до 10 (общо 21 стойности).

Нека разгледаме няколко примера за изрази за приоритет при безизходица.

Пример 1:

Сесия 1 с приоритет за блокиране:Нормална (0)> Сесия 2 с приоритет за блокиране:Ниска (-5)

Жертва в безизходица:  Сесия 2

Пример 2:

Сесия 1 с приоритет на блокиране:Нормална (0) <Сесия 2 с приоритет на блокиране:Висок (+5)

Жертва в безизходица:  Сесия 1

Пример 3

Сесия 1 с приоритет за блокиране:-3> Сесия 2 с приоритет за блокиране:-7

Пример 4:

Сесия 1 с приоритет за блокиране:-5 <Сесия 2 с приоритет за блокиране:5

Жертва в безизходица:  Сесия 1

Затвори на SQL Server с помощта на графики за блокиране

Графиката на безизходица е визуално представяне на процесите в застой, техните заключвания и жертвата на безизходица. Можем да активираме флаговете за проследяване 1204 и 1222 да улавят подробна информация за блокиране в XML и графичен формат. Можем да използваме разширеното събитие system_health по подразбиране за да получим подробности за блокирането. Бърз и лесен начин за интерпретиране на блокирането е чрез графика за блокиране. Нека симулираме състояние на застой и да видим съответната му графика.

За тази демонстрация създадохме таблицата „Клиент и поръчки“ и вмъкнахме няколко примерни записа.

CREATE TABLE Customer (ID INT IDENTITY(1,1), CustomerName VARCHAR(20)) GO CREATE TABLE Orders (OrderID INT IDENTITY(1,1), ProductName VARCHAR(50)) GO INSERT INTO Customer(CustomerName) VALUES ('Rajendra') Go 100 S INSERT INTO Orders(ProductName) VALUES ('Laptop') Go 100

След това отворихме нов прозорец за заявка и активирахме глобално флага за проследяване.

DBCC traceon(1222,-1)

След като активирахме флага за проследяване на блокиране, стартирахме две сесии и изпълнихме заявката в следния ред:

  • Първата сесия стартира транзакция за актуализиране на таблицата с клиенти за клиентски идентификатор 1.
  • Втората сесия стартира транзакция за актуализиране на таблицата с поръчки за идентификатор на поръчка 10.
  • Първата сесия се опитва да актуализира таблицата с поръчки за същия идентификатор на поръчка 10. Втората сесия вече заключва този ред. Сесия 1 е блокирана поради заключванията, държани от сесия 2.
  • Сега за сесия 2 искаме да актуализираме таблицата на клиентите за клиентски идентификатор 1. Тя генерира ситуация в безизходица, при която и двете сесии ID 63 и ID 65 не могат да напреднат.

В този пример SQL Server избира жертва на безизходица (идентификатор на сесия 65) и убива транзакцията. Нека извлечем графиката за блокиране от разширената сесия на събитие system_health.

SELECT XEvent.query('(event/data/value/deadlock)[1]') AS DeadlockGraph FROM ( SELECT XEvent.query('.') AS XEvent FROM ( SELECT CAST(target_data AS XML) AS TargetData FROM sys.dm_xe_session_targets st INNER JOIN sys.dm_xe_sessions s ON s.address = st.event_session_address WHERE s.NAME = ‘system_health’ AND st.target_name = ‘ring_buffer’ ) AS Data CROSS APPLY TargetData.nodes('RingBufferTarget/event[@name="xml_deadlock_report"] ') AS XEventData(XEvent) ) AS source;

Тази заявка ни дава XML в застой, който изисква опитен DBA за интерпретиране на информацията.

Записваме този XML за блокиране с помощта на разширението .XDL и когато отворим XDL файла в SSMS, получаваме графиката за блокиране, показана по-долу.

Тази графика за блокиране предоставя следната информация:

  • Процесни възли:  В овала получавате информация, свързана с процеса.
  • Ресурсни възли:  Ресурсните възли (квадратно поле) предоставят информация за обектите, участващи в транзакциите, заедно с ключалките. В този пример показва RID заключване, защото нямаме индекси и за двете таблици.
  • Ръбове:  Ръб свързва процесния възел и ресурсния възел. Показва собственика на ресурса и режима на заключване на заявката.

Той представлява жертва на безизходица чрез зачеркване на овала в графиката за блокиране.

Можете да уловите информация за блокиране на SQL Server по следните начини:

  • Профилър на SQL сървър
  • Разширени събития на SQL Server
  • Журнали за грешки на SQL Server
  • Проследявания по подразбиране в SQL Server

5 типа блокирания в SQL Server

1) Застой при търсене на отметки

Търсенето на отметки е често срещана застой в SQL Server. Възниква поради конфликт между оператора select и операторите DML (вмъкване, актуализиране и изтриване). Обикновено SQL Server избира оператора select като жертва на безизходица, тъй като не причинява промени в данните и връщането е бързо. За да избегнете търсенето на отметки, можете да използвате покриващ индекс. Можете също да използвате намек за заявка NOLOCK в операторите select, но той чете незаети данни.

2) Застой при сканиране на обхват

Понякога използваме СЕРИАЛИЗИРУЕМО ниво на изолация на ниво сървър или на ниво сесия. Това е ограничително ниво на изолация за контрол на едновременност и може да създаде заключвания за сканиране на диапазон вместо заключвания на ниво страница или ред. В нивото на изолация SERIALIZABLE потребителите не могат да четат данни, ако те са променени, но чакат да бъдат ангажирани в транзакция. По същия начин, ако една транзакция чете данни, друга транзакция не може да ги промени. Той осигурява най-ниския паралел, така че трябва да използваме това ниво на изолация в специфични изисквания на приложението.

3) Каскадно блокиране на ограничение

SQL Server използва връзката родител-дете между таблиците, използвайки ограниченията на външния ключ. В този сценарий, ако актуализираме или изтрием запис от родителската таблица, са необходими необходимите заключвания на дъщерната таблица, за да се предотвратят осиротели записи. За да премахнете тези блокирания, винаги трябва да променяте данните в дъщерна таблица, следвана от родителските данни. Можете също да работите директно с родителската таблица, като използвате опциите DELETE CASCADE или UPDATE CASCADE. Трябва също така да създадете подходящи индекси за колоните с външния ключ.

4) Застой в паралелизъм в рамките на заявка

След като потребител подаде заявка към SQL машината за заявки, оптимизаторът на заявки изгражда оптимизиран план за изпълнение. Той може да изпълни заявката в сериен или паралелен ред в зависимост от цената на заявката, максималната степен на паралелизъм (MAXDOP) и прага на разходите за паралелизъм.

В режим на паралелизъм SQL Server присвоява множество нишки. Понякога за голяма заявка в режим на паралелизъм тези нишки започват да се блокират една друга. В крайна сметка се превръща в застой. В този случай трябва да прегледате плана за изпълнение и вашия MAXDOP и праг на разходите за конфигурации на паралелизъм. Можете също така да посочите MAXDOP на ниво сесия, за да отстраните неизправностите в сценария за блокиране.

5) Обратно блокиране на реда на обекти

При този тип безизходица множество транзакции имат достъп до обекти в различен ред в T-SQL. Това причинява блокиране между ресурсите за всяка сесия и го превръща в безизходица. Винаги искате да осъществявате достъп до обекти в логически ред, така че това да не доведе до ситуация в безизходица.

Полезни начини за избягване и минимизиране на блокиране на SQL Server

  • Опитайте се да поддържате транзакциите кратки; това ще избегне задържането на заключвания в транзакция за дълъг период от време.
  • Достъп до обекти по подобен логически начин в множество транзакции.
  • Създайте покриващ индекс, за да намалите възможността от безизходица.
  • Създайте индекси, за да съответстват на колоните с външния ключ. По този начин можете да елиминирате безизходицата поради каскадна референтна цялост.
  • Задайте приоритети за блокиране с помощта на променливата на сесията SET DEADLOCK_PRIORITY. Ако зададете приоритет на блокиране, SQL Server убива сесията с най-нисък приоритет.
  • Използвайте обработката на грешки, като използвате блоковете try-catch. Можете да хванете грешката в застой и да стартирате отново транзакцията в случай на жертва на безизходица.
  • Променете нивото на изолация на ПРОЧЕТЕНЕ НА ИЗОЛАЦИЯ НА МОМЕНТНА СНИМКА или ИЗОЛАЦИЯ НА МОМЕНТНА СНИМКА. Това променя механизма за заключване на SQL Server. Въпреки това, трябва да внимавате при промяна на нивото на изолация, тъй като това може да повлияе негативно на други заявки.

Съображения за блокиране на SQL Server

Блокировките са естествен механизъм в SQL Server за избягване на заключване на сесията и изчакване на други ресурси. Трябва да улавяте заявки в застой и да ги оптимизирате, така че да не влизат в конфликт помежду си. Важно е да уловите ключалката за кратък период от време и да я освободите, така че другите заявки да могат ефективно да я използват.

Случват се задънки на SQL Server и докато SQL Server вътрешно се справя със ситуации на застой, трябва да се опитате да ги сведете до минимум, когато е възможно. Някои от най-добрите начини за премахване на блокиране са чрез създаване на индекс, прилагане на промени в кода на приложението или внимателно инспектиране на ресурсите в графика за блокиране. За повече съвети как да избегнете заглушения на SQL, вижте нашата публикация: Избягване на блокиране на SQL с настройка на заявката.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Присъединяване към MAX запис за дата в групата

  2. Трябва ли да изберете типовете данни MONEY или DECIMAL(x,y) в SQL Server?

  3. Какво прави SQL изявлението sargable?

  4. Разберете дали ограничението CHECK е на ниво колона или на ниво таблица в SQL Server (примери за T-SQL)

  5. Как да пиша с помощта на BCP към отдалечен SQL сървър?