MVCC — bir ma’lumotning bir nechta versiyasini saqlash orqali parallel transactionlarning o‘qish va yozish jarayonlarini kamroq bloklashga yordam beradigan concurrency control usuli. Uning to‘liq nomi Multi-Version Concurrency Control hisoblanadi.
MVCC readerga ma’lum snapshotga mos row versiyasini ko‘rsatadi. Writer yangi versiya yaratishi mumkin. Shu sababli ko‘p read operationlar writer bilan to‘g‘ridan-to‘g‘ri lock conflict qilmaydi.
Row versiyasi
Row update qilinganda eski qiymat darhol o‘chirib yozilmasligi mumkin.
Masalan:
v1: status = pending
v2: status = paid
Eski transaction v1ni, yangi transaction v2ni ko‘rishi mumkin.
Qaysi versiya visible ekanini transaction metadata belgilaydi.
Snapshot
Transaction yoki statement boshlanganda ko‘rinadigan transactionlar to‘plami aniqlanadi.
Bu snapshot.
Snapshot quyidagilarni hisobga olishi mumkin:
- commit qilingan transactionlar;
- hali davom etayotgan transactionlar;
- joriy transaction;
- transaction ID chegaralari.
Isolation level snapshotning qancha vaqt saqlanishini belgilaydi.
Statement snapshot
Read Committed darajasida har statement yangi snapshot olishi mumkin.
Bir transaction ichidagi ikki SELECT orasida boshqa transaction commit qilgan o‘zgarish ko‘rinadi.
Bu non-repeatable readga imkon berishi mumkin.
Transaction snapshot
Repeatable Readga yaqin modelda transaction davomida bir snapshot saqlanadi.
Ayni query qayta bajarilganda bir xil committed tarixiy holat ko‘rinadi.
Yangi rowlar ham snapshot qoidasi bo‘yicha ko‘rinmasligi mumkin.
Visibility
Row versiyasi transactionga ko‘rinishi uchun:
- uni yaratgan transaction commit qilganmi;
- snapshotdan oldinmi;
- row keyin delete qilinganmi;
- delete qilgan transaction commit qilganmi;
- joriy transaction o‘zgarishimi
kabi qoidalar tekshiriladi.
Bu metadata har row yoki undo logda saqlanishi mumkin.
Update
Writer rowning yangi versiyasini yaratadi.
Eski versiya active snapshotlar uchun saqlanadi.
Ikki writer ayni rowni o‘zgartirmoqchi bo‘lsa write-write conflict va lock yuz beradi.
MVCC barcha locklarni yo‘q qilmaydi.
Delete
Delete rowni darhol fizik yo‘qotmasligi mumkin.
Row ma’lum transactiondan boshlab ko‘rinmaydigan versiyaga aylanadi.
Eski snapshotlar uni hali ko‘rishi mumkin.
Keyinchalik vacuum yoki purge fizik joyni tozalaydi.
Reader va writer
MVCCning asosiy afzalligi:
reader writer’ni kamroq bloklaydi
writer reader’ni kamroq bloklaydi
Reader eski committed versiyani ko‘radi.
Lekin schema lock, unique constraint, explicit lock va DDL bloklanishi mumkin.
Write-write conflict
Ikki transaction ayni rowni parallel yangilasa ikkalasi mustaqil yakuniy versiya yaratishi mumkin emas.
- biri kutadi;
- conflict xatosi beradi;
- keyingi versionga update qiladi;
- serializable abort
modelidan foydalanadi.
Lost update’dan himoya isolation va query shakliga bog‘liq.
Lost update
Ikki transaction bir qiymatni o‘qib, alohida hisoblab, keyin bir-birining update’ini bosishi mumkin.
Masalan, counter ikkala transactionda 10 deb o‘qiladi va 11 yoziladi.
Atomic SQL:
UPDATE counters
SET value = value + 1;
yoki version check ishlatiladi.
Write skew
Ikki transaction bir xil invariantni o‘qib, turli rowlarni yangilashi mumkin.
Row conflict bo‘lmasa ham umumiy qoida buziladi.
Serializable isolation, explicit lock yoki constraint kerak bo‘lishi mumkin.
MVCC snapshot isolation har doim serializable emas.
Undo log modeli
Ayrim database’lar rowning joriy versiyasini table’da, eski versiyalarini undo logda saqlaydi.
Reader snapshot uchun undo chain bo‘ylab oldingi qiymatni tiklaydi.
Uzoq transaction uzun undo history saqlanishiga sabab bo‘ladi.
Append-version modeli
Boshqa tizimlar yangi row versiyasini table storage’ning o‘zida yozishi mumkin.
Eski versiyalar dead tuple bo‘lib qoladi.
Vacuum keyinchalik ularni tozalaydi.
Har modelning storage va cleanup xususiyatlari farq qiladi.
Vacuum yoki purge
Hech bir active snapshotga kerak bo‘lmagan eski versiyalar olib tashlanadi.
Cleanup ortda qolsa:
oshadi.
Uzoq transaction cleanup horizonni ushlab turishi mumkin.
Transaction ID
Row versiyalarining yaratilish va o‘chirish holati transaction ID bilan belgilanishi mumkin.
Transaction ID cheklangan diapazonga ega bo‘lsa wraparound himoyasi talab qilinadi.
Freeze yoki boshqa metadata normalization ishlatiladi.
MVCC va isolation
MVCC implementation mexanizmi.
Isolation esa transactionga beriladigan semantik kafolat.
Bir xil MVCC tizimi:
- Read Committed;
- Repeatable Read;
- Serializable
darajalarini turli qo‘shimcha nazorat bilan berishi mumkin.
Serializable MVCC
Serializable Snapshot Isolation transactionlar o‘rtasidagi dependencylarni kuzatib, xavfli cycle bo‘lsa birini abort qilishi mumkin.
Bu readerlarni keng lock qilmasdan serializable natija berishga intiladi.
Application serialization failure’ni retry qiladi.
Index va MVCC
Index bir key uchun bir nechta row versioniga entry saqlashi mumkin.
Index scan keyin table visibility’ni tekshiradi.
Index-only scan uchun visibility metadata yoki map kerak bo‘lishi mumkin.
Dead versionlar index bloatiga sabab bo‘ladi.
Monitoring
Kuzatiladi:
- eng eski transaction;
- active snapshot;
- dead row;
- undo log;
- vacuum lag;
- transaction ID yoshi;
- conflict;
- serialization failure.
Uzoq idle in transaction session production bloatining asosiy sabablaridan biri bo‘lishi mumkin.
Visibility map
Ayrim storage engine page’dagi barcha rowlar barcha transactionlar uchun visible ekanini metadata’da belgilaydi.
Bu index-only scan va vacuum optimizationiga yordam beradi.
Page yangilansa belgi qayta tekshirilguncha olib tashlanadi.
Snapshot export
Bir transaction snapshotini boshqa sessionlarga berish imkoniyati bo‘lishi mumkin.
Bu parallel report workerlari bir xil consistent database holatini ko‘rishi uchun ishlatiladi.
Snapshot uzoq saqlansa cleanup horizon ortda qoladi.
Bog‘liq tushunchalar
Multi-Version Concurrency Control, Snapshot, Isolation level, Row version, Vacuum, Transaction ID, Write skew, Lost update, Serializable isolation, Concurrency control