Като част от есенната поредица дни за обучение на база данни на Quest, Брент Озар, сертифициран майстор на Microsoft, представи урок за „Избягване на безизходи с настройка на заявки“. Програмата се фокусира върху трите проблема с паралелността, които възникват в SQL Server, три начина за тяхното коригиране и един начин, който изглежда да ги коригира, но всъщност не.
Проблеми с паралелността:Заключване, блокиране и блокиране в SQL Server
Какви са проблемите с паралелността? Те се случват, когато заявките се опитват да избегнат конфликт помежду си относно обекти на база данни като таблици. Те са:
- Заключване – Заявките правят това през цялото време, за да попречат на други заявки да използват таблица по едно и също време. Това е нормална операция с база данни.
- Блокиране – Това се случва, когато една заявка има нормално заключване, но друга заявка се опитва да получи същото заключване. Втората заявка трябва да изчака толкова дълго, колкото е необходимо, за да освободи първата заявка. В зависимост от естеството на първата заявка, втората може да чака много кратко време или много дълго време. Именно тези дълги чакания наистина влияят на производителността.
- Заключване – Заключване възникват, когато една заявка взема заключване, друга заявка взема различно заключване и след това всяка иска да придобие заключване на другата. SQL Server разрешава това, като определя една от заявките като жертва и я убива, за да прекъсне противопоставянето. Въпреки че една от заявките може да продължи, това също оказва влияние върху производителността.
Отстраняване на проблеми с едновременността
Независимо дали изпитвате блокиране или блокиране в SQL Server, има начини за отстраняване на проблеми с паралелността. Брент представи тези три метода и прекара по-голямата част от останалата част от сесията, фокусирайки се върху втория – коригиране на лош код.
- Имайте достатъчно индекси за да направите заявките си бързи, но не толкова много, че да забавят нещата, като карат заявките да задържат повече заключвания за по-дълъг период от време
- Настройте транзакционния си код, така че заявките да работят през таблици в същия предвидим ред всеки път
- Използвайте правилното ниво на изолация за нуждите на приложението си
Докато скочи в практическата част на програмата, Брент коментира използването на оператори NOLOCK за блокиране и блокиране. Той предупреди, че NOLOCK всъщност не решава тези проблеми, защото разчита на „мръсно четене“ – по същество игнорира заключванията на редове на други заявки.
В демонстрацията си на това, използвайки базата данни на Stack Overflow, той създаде проста заявка, която търси и брои хора на име „Алекс“. След това той създаде друга заявка, която ще изведе актуализация за хора, които не на име Алекс — без вмъкване или изтриване на записи. Едната заявка не трябва да има нищо общо с другата. Но провеждането им заедно води до различни резултати в броя на хората на име Алекс. Това е така, защото NOLOCK ви позволява да видите данни, които не са били ангажирани, което води до произволни резултати, които не можете да предвидите. Това се случва само при паралелност.
Очевидно е необходимо по-добро решение за блокиране и блокиране в SQL Server, което не води до произволни и непредвидими резултати.
По-добро решение за SQL блокиране
След това Брент демонстрира как да поправите блокиране, като промените кода, който го причинява. Първото му демо показа проста ситуация, включваща две маси, така че публиката може да види задънена улица в забавен каданс, докато се случи. Тъй като SQL Server търси блокиране на всеки 5 секунди и убива заявката, която е най-лесна за връщане назад, успяхме да видим как се появява жертвата на безизходица.
В проста ситуация се прилага най-общият съвет, а това е да докосвате таблиците в един и същи ред всеки път, когато създавате заявки. Това обикновено ще предпази заявките от блокиране взаимно.
Какво ще кажете за по-сложните заявки? За този сценарий Брент използва по-реалистична ситуация, която лесно може да възникне в Stack Overflow, където двама души гласуват взаимно за въпроси. Тъй като в двете транзакции участват едни и същи потребители, това води до безизходица.
Тук не е достатъчно да работите през всяка таблица в един и същ ред всеки път, но също така е необходимо да се сведе до минимум броят на докосванията на всяка таблица. Както Брент обясни, корекцията може да включва някакъв грозен код, който причинява блокиране на заявките, но поне не блокиране. В този случай блок с кратка продължителност, който позволява на двете заявки да се изпълняват до завършване, е по-добър от блокиране, което прекратява една от тях.
Никой не иска да променя кода в стотици заявки, така че се съсредоточете върху тези, които постоянно блокират, премахнете всички ненужни редове от транзакцията и не се страхувайте да въведете блок, за да избегнете блокиране.