Ян. 222007
 

Основното действие, което се случва в една БД, дори и при OLTP системи, е извличането на данни. Четенето е десетки пъти по-често от промяната.

И така, какво става при извличане на данни от БД?

Инициатор на четенето е процеса (thread, под Windows), който пуска заявката. Четенето се извършва от същият този процес.

Първото нещо е да се провери дали този блок е кеширан в паметта. Така би се избегнало „скъпото“ и бавно четене от дисковата подсистема. Обикновено в една добре оразмерена система над 80-90% от четенията се задоволяват от кеша.

Но за целта не е добре да се прочита цялата памет за всяко едно блокче. Когато процеса определи адреса (DBA, Database Block Address) на блока, който трябва да се прочете, този процес се хешира през специална хеш функция, която връща адрес на набор от блокове (bucket), намиращи се в свързан списък в паметта (cache buffer chain). Процеса изчита този списък за да извлече желаният блок. За да се изчете този списък се изисква неговият latch в share mode, но това си е тама на друга лекция

Ако търсеният блок бъде намерен в този списък, при прочитането му се увеличава неговия touch count индикатор (не винаги). Увеличаването на този touch count не е защитено от latch, т.е. може да се “загубят” някои повишения, но това не е голям проблем (не си заслужава да се прави latch специално за това). Touch count показателя се използва за да се поддържат в паметта най-използваните блокове. Поддържането на този индикатор също е тема за друга лекция.

Ако не бъде намерен блокът се задейства друг механизъм:
– взема се свободен LRU буфер чрез LRU latch (ако няма – следва чакане)
– този LRU буфер се закача към намереният cache buffer chain
– блока се извлича от диска в буфера и буфера става I/O буфер. В този момент всякак друга сесия, която иска да го прочете, трябва да се изчака (busy buffer wait)
Ако няма място (достигнато е максималното количество заета памет за кеш), се „изхвърлят“ по-малко използвани блокове, за да се направи място за новите. Тук трябва да се отбележи, че за да бъде изхвърлен един блок от кеша, той не трябва да бъде “dirty”, т.е. ако е променян, трябва промените да са записани на диска. Това се прави от фоновия процес DBWR. Докато се случи това изчистване на буфери, потребителската сесия чака.

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

В този момент се проверява SCN номера в хедъра на блока. SCN е съкращение от system commit number или system change number. В началото на изпълнението на каквато и да е заявка се запомня SCN, при който започва тя. Ако SCN на прочетения блок е по-нов, това означава, че блока е бил променен от друг потребител след като е започнало изпълнението на заявката (но преди да бъде прочетен). В такъв случай се взима адреса на транзакцията, променила блока (той се намира в ITL секцията в хедъра на блока), намира се нейният undo сегмент и от него се извлича т.нар. before image на блока – състоянието му от преди да го промени. Отново се проверява SCN на реконструираният блок. Ако пак е по-нов от SCN на заявката, се нямира още по-стара версия и т.н., докато не се намери блока във вида, в който е бил в началото на изпълнението на заявката. Ако няма повече дани в undo/rollback сегмента, а блока не е възстановен до желният SCN, се получава печално известната грешка ORA-1555 Snapsjot too old
По този начин всяка заявка получава данните във вид, консистентен към началото на изпълнението си, като това се получава без никакви заключвания за четене.
Ето един пример от документацията на Oracle Database:
***
Заявката започва да се изпълнява. Запомян се текущият SCN (в случая, 10023). Блоковете се четат в реда, в който са необходими за заявката. Ако някой блок е по-нов от SCN 10023, възстановява се неговото състояние от undo/rollback сегментите.

 Posted by at 9:37

  5 Responses to “Четене на данни в Oracle”

  1. лекцията беше супер интересна… благодаря за което 🙂

  2. Да, много се зарадвах на „отзвука“ от лекцията. Постигнах по-силен резултат от колкото се надявах. И още малко си вдигнах самочувствието на „кадърен лектор“ 😉

  3. […] DLM управлява (основно) блокове в buffer cache. В не-клъстерна среда, ако един процес на един има нужда да прочете или промени даден блок, той поглежда дали е наличен в buffer cache (виж “Четене на данни в Oracle”). Ако не е, прочита го от диска, променя го и готово. Ако някой друг го е променил преди това, то или промените са в Buffer cache (и се работи директно там), или са записани на диска и ще бъдат прочетени. […]

  4. […] се свърши. Благодарение на супер подлият механизъм за четене на данни в Oracle, промените се случват върху самите данни преди да се […]

  5. За мен беше изключително полезно да прочета тази статия. Харесва ми опростеният начин на обясненията, което винаги е по-добрият начин да се обясни една сложна архитектура. Браво Яворе, ще си купя книга от теб когато решиш да издадеш такава. Единствено се загубих малко в следното изречение „свободен LRU буфер чрез LRU latch“. Какво точно е това „LRU буфер чрез LRU latch“ ми е малко мъгла, но иначе супер статия.

Sorry, the comment form is closed at this time.