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

Нивото на изолация, което може да се сериализира

[ Вижте индекса за цялата серия ]

Голяма част от производствения T-SQL код е написана с имплицитното допускане, че основните данни няма да се променят по време на изпълнение. Както видяхме в предишната статия от тази поредица, това е опасно предположение, тъй като данните и записите в индекса могат да се движат под нас, дори по време на изпълнението на един израз.

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

Като оставим това настрана за секунда, идеята за защита на важна област от T-SQL кода с транзакция изглежда се основава на неразбиране на защитите, предлагани от свойствата на ACID транзакцията. Важният елемент от това съкращение за настоящата дискусия е Изолация Имот. Идеята е, че използването на транзакция автоматично осигурява пълна изолация от ефектите на други едновременни дейности.

Истината на въпроса е, че транзакциите под SERIALIZABLE посочете само степен на изолация, което зависи от действащото в момента ниво на изолация на транзакциите. За да разберем какво означава всичко това за нашето ежедневие T SQL практиките за кодиране, първо ще разгледаме подробно нивото на изолация, което може да се сериализира.

Сериализираща се изолация

Serializable е най-изолираното от стандартните нива на изолация на транзакции. Също така е и по подразбиране ниво на изолация, определено от стандарта SQL, въпреки че SQL Server (като повечето търговски системи за бази данни) се различава от стандарта в това отношение. Нивото на изолация по подразбиране в SQL Server е извършено за четене, по-ниско ниво на изолация, което ще разгледаме по-късно в поредицата.

Дефиницията на сериализиращото се ниво на изолация в стандарта SQL-92 съдържа следния текст (подчертавам мое):

Изпълнението, което може да се сериализира, се дефинира като изпълнение на операциите на едновременно изпълнявани SQL транзакции, което произвежда същия ефект като някои серийни изпълнения на същите тези SQL транзакции. Серийното изпълнение е такова, при което всяка SQL-транзакция се изпълнява до завършване, преди да започне следващата SQL-транзакция.

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

Казано по друг начин, на реална система от база данни е позволено да се припокрива физически изпълнението на сериализиращи се транзакции във времето (като по този начин се увеличава едновременността), докато ефектите от тези транзакции все още съответстват на някакъв възможен ред на серийно изпълнение. С други думи, сериализиращите се транзакции са потенциално сериализиращи се вместо да е действително сериализиран .

Логически сериализиращи се транзакции

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

Помислете за таблица, която съдържа голям брой редове, пет от които удовлетворяват някакъв интересен предикат на заявка. Сериализирана транзакция T1 започва да брои броя на редовете в таблицата, които съответстват на този предикат. Известно време след T1 започва, но преди да извърши, втора сериализираща се транзакция T2 започва. Транзакция T2 добавя четири нови реда, които също отговарят на предиката на заявката към таблицата, и извършва ангажименти. Диаграмата по-долу показва времевата последователност от събития:

Въпросът е колко реда трябва да бъде заявката в сериализираща се транзакция T1 брои? Не забравяйте, че тук мислим само за логическите изисквания, така че избягвайте да мислите кои ключалки могат да бъдат взети и така нататък.

Двете транзакции физически се припокриват във времето, което е добре. Сериализиращата се изолация изисква само резултатите от тези две транзакции да съответстват на някакво възможно серийно изпълнение. Очевидно има две възможности за логичен сериен график на транзакциите T1 и T2 :

Използване на първия възможен сериен график (T1 след това T2 ) T1 заявката за броене ще види пет реда , тъй като втората транзакция не започва, докато не завърши първата. Използвайки втория възможен логически график, T1 заявката ще преброи девет реда , тъй като вмъкването на четири реда е логически завършено, преди транзакцията да е започнала.

И двата отговора са логически правилни при изолация с възможност за сериализиране. Освен това не е възможен друг отговор (така че транзакция T1 не може да преброи седем реда, например). Кой от двата възможни резултата действително се наблюдава зависи от точното време и редица подробности за внедряването, специфични за използваната машина за база данни.

Имайте предвид, че не стигаме до заключението, че транзакциите всъщност са по някакъв начин пренаредени във времето. Физическото изпълнение е свободно да се припокрива, както е показано на първата диаграма, стига механизмът на базата данни да гарантира, че резултатите отразяват какво би се случило, ако бяха изпълнени в една от двете възможни серийни последователности.

Сериализиращи се и феномените на паралелност

В допълнение към логическата сериализация, SQL стандартът също така споменава, че транзакция, работеща на ниво на изолация, която може да се сериализира, не трябва да изпитва определени явления на едновременност. Не трябва да чете незаети данни (без мръсно четене ); и след като данните бъдат прочетени, повторението на същата операция трябва да върне точно същия набор от данни (повтаряеми четения без фантоми ).

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

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

Сериализиращи се реализации

Случайно SQL Server използва заключваща реализация на сериализиращото се ниво на изолация, където физическите заключвания се придобиват и задържат до края на транзакцията (оттук и остарялата подсказка за таблица HOLDLOCK като синоним на SERIALIZABLE ).

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

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

Заключването е само една от възможните физически реализации на сериализиращото се ниво на изолация. Трябва да внимаваме мислено да разделим конкретното поведение на заключващата реализация на SQL Server от логическата дефиниция на сериализиращ се.

Като пример за алтернативна физическа стратегия вижте реализацията на PostgreSQL на изолиране на моментни снимки с възможност за сериализиране, въпреки че това е само една алтернатива. Разбира се, всяко различно физическо изпълнение има своите силни и слаби страни. Като настрана, имайте предвид, че Oracle все още не предоставя напълно съвместимо изпълнение на сериализиращото се ниво на изолация. Има ниво на изолация с име може да се сериализира, но не гарантира наистина, че транзакциите ще се изпълняват според някакъв възможен сериен график. Вместо това Oracle предоставя изолиране на моментни снимки когато се изисква сериализиращо се, почти по същия начин, по който PostgreSQL направи преди изолирането на моментни снимки с възможност за сериализиране (SSI ) беше внедрен.

Изолирането на моментна снимка не предотвратява аномалии на едновременност като изкривяване при запис, което не е възможно при наистина сериализираща се изолация. Ако се интересувате, можете да намерите примери за изкривяване на запис и други ефекти на едновременност, разрешени от изолирането на моментни снимки на връзката на SSI по-горе. Ще обсъдим също така реализацията на SQL Server на нивото на изолация на моментни снимки по-късно в поредицата.

Изглед към момента?

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

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

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

Следващия път

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

[ Вижте индекса за цялата серия ]


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

  2. Как да изтриете колона в таблицата

  3. Лоши навици :Фокусиране само върху дисковото пространство при избора на ключове

  4. Използване на ODBC данни в RapidMiner

  5. Как да изчислим възрастта от датата на раждане в SQL