Розуміння SQL Server LOCKS на запитах SELECT


79

Мені цікаво, яку користь використовувати SELECT WITH (NOLOCK)в таблиці, якщо єдиними іншими запитами, що впливають на цю таблицю, є SELECTзапити.

Як це обробляє SQL Server? Чи SELECTзапит заблокує інший SELECTзапит?

Я використовую SQL Server 2012 та Linq-to-SQL DataContext.

(РЕДАКТУВАТИ)

Про продуктивність:

  • Чи SELECTповинен би 2- й чекати закінчення 1-го, SELECTякщо використовувати заблокований SELECT?
  • Проти a SELECT WITH (NOLOCK)?

Відповіді:


178

A SELECTв SQL Server розмістить загальний замок у рядку таблиці, а другий SELECTтакож потребує спільного блокування, і вони сумісні між собою.

Тож ні - ніхто SELECTне може заблокувати іншого SELECT.

Для чого використовується WITH (NOLOCK)підказка запиту, це мати можливість читати дані, які перебувають у процесі вставки (за допомогою іншого з’єднання) і які ще не були зафіксовані.

Без цього натяку на запит a SELECTможе бути заблоковано читанням таблиці за допомогою поточного INSERT(або UPDATE) оператора, який розміщує ексклюзивний замок на рядки (або, можливо, цілу таблицю), доки транзакція цієї операції не буде здійснена (або відкатана).

Проблема WITH (NOLOCK)підказки полягає в тому, що ви, можливо, читаєте рядки даних, які взагалі не збираються вставляти, зрештою (якщо INSERTтранзакція відкатана) - отже, наприклад, у вашому звіті можуть бути дані, які ніколи насправді не були передані в базу даних .

Існує ще одна підказка, яка може бути корисною - WITH (READPAST). Це вказує SELECTкоманді просто пропускати будь-які рядки, які вона намагається прочитати і які виключно заблоковані. Він SELECTне заблокує і не буде читати будь-які "брудні" нефіксовані дані - але він може пропустити деякі рядки, наприклад, не показати всі ваші рядки в таблиці.


1
Приємна відповідь, велике спасибі! Чи SELECTміг би це мати вплив (на сотні запитів) для використання WITH (NOLOCK)без причини?
Френсіс П

3
Ми використовуємо з nolock у 99,5% наших вибору, не жартуємо. Якщо адміністратор оновлює запис користувача, ви не хочете, щоб звіт стояв там і чекав закінчення всієї розподіленої транзакції. Тож їхні старі дані відображаються у звіті. Хто дбає? Якби звіт був запущений за секунду до того, це ті самі дані, які були б там із rowlock. Єдине, що викликає занепокоєння, - це дані, які ще не зафіксовані. Якщо ви показуєте "замовлення за останню годину", це потенційно може бути проблемою, але крихітною, крихітною проблемою порівняно зі збільшенням швидкості / паралельності.
Brian White

5
Крім того, оскільки "звіт" було викинуто як приклад, звіти, як правило, стосуються періоду часу, який не становить останніх 5 хвилин. Звітування про дані минулого місяця з nolock - ну це не схоже на те, що дані збираються повернутися через місяць.
Brian White

2
@FrancisP: ні, якщо ви вставляєте невелику кількість рядків - у цьому випадку він просто блокує нові рядки, що вставляються. Якщо ви вставите більше приблизно 5000 рядків одночасно - тоді відбудеться посилення блокування, і вся таблиця буде виключно заблокована.
marc_s

1
Дуже приємна відповідь .. Я відчував себе як все в одному підручнику для блокування SQL !! рада, що потрапила сюди!
digitalally_inspired

32

Щодо продуктивності ви постійно концентруєте увагу на обраному.
Спільний доступ не блокує читання.
Оновлення спільних блокувальних блоків.
Якщо у вас є сотні спільних блокувань, потрібно буде оновити деякий час, щоб отримати ексклюзивний замок, оскільки він повинен почекати, поки загальні блокування очистяться.

За замовчуванням select (читання) робить спільне блокування.
Спільні (S) блокування дозволяють паралельним транзакціям читати (ВИБРАТИ) ресурс.
Спільний замок, оскільки це не впливає на інші селекти (1 або 1000).

Різниця полягає в тому, як операції оновлення та вставки ефектів nolock та спільних ефектів блокування.

Жодні інші транзакції не можуть змінювати дані, поки на ресурсі існують загальні (S) блокування.

Спільний замок блокує оновлення!
Але nolock не блокує оновлення.

Це може мати величезний вплив на продуктивність оновлень. Це також впливає на вставки.

Брудне читання (nolock) просто звучить брудно. Ви ніколи не збираєтесь отримувати часткові дані. Якщо оновлення змінює Джона на Саллі, ти ніколи не отримаєш Веселого.

Я багато використовую спільні замки для одночасності. Дані застаріли, як тільки їх прочитано. Читання Джона, яке змінюється на Саллі наступної мілісекунди, - це застарілі дані. Читання Саллі, яке відкочує Джона наступної мілісекунди, - це несвіжі дані. Це на рівні мілісекунд. У мене є завантажувач даних, який займає 20 годин, якщо користувачі беруть спільні блокування, а 4 години - це те, що користувачі не беруть блокування. Спільні замки в цьому випадку спричиняють застарілі дані на 16 годин.

Не використовуйте nolocks неправильно. Але їм є місце. Якщо ви збираєтеся вирізати перевірку, коли байт встановлено в 1, а потім встановити його в 2, коли перевірка вирізана - не час для nolock.


2
Дякую. Ми бачимо подібні експлуатаційні характеристики. Наш сайт не працював би, якщо нам потрібні замки для читання, і наслідки відсутності його в більшості випадків просто незначні.
Брайан Уайт

@BrianWhite Дякую. Хтось отримує. І я беру багато блокування таблиць на оновлення та вставляю. Заходьте, робіть це, і виходьте - це мій підхід.
папарацці

2
Брудне читання (nolock) просто звучить брудно. Ви ніколи не збираєтесь отримувати часткові дані. Якщо оновлення змінює Джона на Саллі, ти ніколи не отримаєш Веселого. - ми читаємо Джона, так?
MonsterMMORPG

2
Оновлення на сервері sql використовують блокування оновлення (U), яке згодом перетворюється на ексклюзивне блокування (X). (див. madeiradata.com/role-update-lock-sql-server ) Блокування оновлення не блокує спільні блокування, але ексклюзивний блокування блокує всі інші блокування (див. msdn.microsoft.com/en-us/library/ms186396(v= sql.105) .aspx ).
колобок

@kolobok збирається оновити деякий час, щоб отримати ексклюзивний замок
папарацці

10

Я повинен додати важливий коментар. Усі це згадуютьNOLOCK читає лише брудні дані. Це не точно. Також можливо, що ви отримаєте один і той же рядок двічі, або весь рядок буде пропущено під час читання. Причина в тому, що ви можете запитати деякі дані одночасно, коли SQL Server перебалансує b-дерево.

Перевірте інші теми

https://stackoverflow.com/a/5469238/2108874

http://www.sqlmag.com/article/sql-server/quaere-verum-clustered-index-scans-part-iii.aspx )

За допомогою підказки NOLOCK (або встановлення рівня ізоляції сеансу для READ UNMOMMITTED) ви повідомляєте SQL Server, що не очікуєте узгодженості, тому немає ніяких гарантій. Пам’ятайте, однак, що „суперечливі дані” означає не лише те, що ви можете побачити незавершені зміни, які згодом були відкочевані, або зміни даних у проміжному стані транзакції. Це також означає, що під час простого запиту, який сканує всі дані таблиці / індексу, SQL Server може втратити позицію сканування, або в кінцевому підсумку ви отримаєте той самий рядок двічі.


9

У моїй роботі у нас дуже велика система, яка працює на багатьох ПК одночасно, з дуже великими таблицями з сотнями тисяч рядків, а іноді і з мільйонами рядків.

Коли ви робите SELECT на дуже великій таблиці, скажімо, ви хочете знати кожну транзакцію, здійснену користувачем за останні 10 років, і первинний ключ таблиці побудований не ефективно, запит може зайняти кілька хвилин бігти.

Тоді наш додаток може запустити мене на багатьох ПК одночасно, отримуючи доступ до однієї бази даних. Отже, якщо хтось намагається вставити в таблицю, яку читає інший SELECT (на сторінках, які намагається прочитати SQL), тоді може статися БЛОКУВАННЯ, і дві транзакції блокують одна одну.

Нам довелося додати "НЕ БЛОКУВАННЯ" до нашого оператора SELECT, оскільки це був величезний SELECT на таблиці, який багато використовується одночасно багатьма користувачами, і ми постійно мали LOCKS.

Не знаю, чи достатньо зрозумілий мій приклад? Це приклад із реального життя.


Дякую за приклад, але мені цікаво лише про запити SELECT, що впливають на інші запити SELECT (у тій самій таблиці) ..
Френсіс П

1
Вони не будуть, але оператор select може бути частиною транзакції, що включає оновлення. Оновити tbl встановити x = (вибрати макс (y) з tbl) де z = (вибрати min (a) з tbl). Якщо у вас є паралельний вибір z з tbl, інші селекти не блокують його, але оновлення є.
Brian White

1
У мене виникла саме ця проблема, через яку тривалий
селектор

2
Транзакції не блокують одна одну - вибір заблокує оновлення. Ось кілька цікавих посилань, які щойно допомогли мені зрозуміти трохи більше про те, як це працює: перший один другий
JonnyRaa

@JonnyLeeds: Ваше друге посилання вже не працює. Ось заархівоване посилання на SQL Server: Основи блокування
Стомі

3

SELECT WITH (NOLOCK)Дозволяє зчитує з непідтверджених даних, що еквівалентно , що мають READ UNCOMMITTEDвстановлений рівень ізоляції на вашій базі даних. NOLOCKКлючові слова дозволяють більш тонко деталізований контроль , ніж установка рівня ізоляції на всю базі даних.

У Вікіпедії є корисна стаття: Вікіпедія: Ізоляція (системи баз даних)

Це також детально обговорюється в інших статтях про stackoverflow.


Дякуємо rghome за додаткову інформацію, яку ви надали.
Френсіс П

Ось чому я вважаю за краще використовувати підказку READUNCOMMITTED(псевдонім для NOLOCK), коли такий є дійсним випадком використання. Це робить фактичну операцію, яка насправді не “без замків”, менш зрозумілою.
user2864740

1

вибрати без блокування - вибере записи, які можуть вставлятись / не вставлятись. ви прочитаєте брудні дані.

наприклад - скажімо, транзакція вставляє 1000 рядків, а потім не вдається.

коли ви оберете - ви отримаєте 1000 рядків.


Але що робити, якщо жоден запис не передбачається вставляти в цю таблицю, чи залишається актуальним функція NO LOCK?
Френсіс П

ні, це не так. оскільки читання використовує спільний замок, який можна отримати більше ніж за 1 сеанс. немає можливості забруднити дані.
Royi Namir

Я радше не відповідаю на те, у чому я не впевнений. :-)
Рої Намір
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.