Write skew — ikki concurrent transaction bir xil mantiqiy shartni o‘qib, turli qatorlarni yangilashi natijasida umumiy biznes invariantini buzadigan concurrency anomaly. U snapshot isolationda, transactionlar bir-birining yozgan qatoriga bevosita tegmagani uchun conflict aniqlanmasdan commit bo‘lishi mumkin.
Klassik holat
Shifoxonada kamida bitta shifokor navbatchi qolishi kerak. doctors jadvalida A va B ikkalasi on_call=true. Ikki transaction bir vaqtda snapshot oladi:
- A transaction ikkala shifokor navbatchi ekanini ko‘rib, A ni o‘chiradi.
- B transaction ayni eski snapshotni ko‘rib, B ni o‘chiradi.
- Ular turli qatorlarni yangilagani uchun row-level write conflict yo‘q.
- Ikkalasi commit qilgach navbatchi qolmaydi.
Har transaction o‘zi ko‘rgan holatda qoidaga rioya qilgan, ammo yakuniy holat invariantni buzgan.
Lost update’dan farqi
Lost update’da ikki transaction odatda ayni rowning eski qiymatini o‘qib, yangi qiymat yozadi va bittasining o‘zgarishi yo‘qoladi. Write skew’da yozuvlar turli qatorlarga tushadi. Shu sabab simple row lock yoki version column faqat o‘zgartirilayotgan satrga qo‘llansa yetmasligi mumkin.
Muammo predicatga bog‘liq: “kamida bitta active row”, “jami limitdan oshmasin” yoki “vaqt oralig‘i ustma-ust tushmasin”. Predicate’ga mos barcha potensial qatorlar conflict doirasiga kiradi.
Isolation bilan bog‘liqlik
Snapshot isolation transactionga barqaror ko‘rinish beradi va dirty readni cheklaydi. U write–write conflictni aniqlashi mumkin, ammo read–write dependency siklini har doim abort qilmaydi. Serializable isolation database’ga bunday natijani ketma-ket bajarilish bilan moslashtirish vazifasini beradi.
PostgreSQL Serializable Snapshot Isolation dangerous dependency patternlarni kuzatib, transactionlardan birini serialization failure bilan bekor qilishi mumkin. Application bunday xatoni butun transaction sifatida retry qiladi.
Himoya usullari
Invariant database constraint bilan ifodalansa eng markaziy himoya hosil bo‘ladi. Oddiy check constraint boshqa qatorlarni query qila olmaydi; exclusion constraint, unique index yoki alohida summary row ba’zi qoidalarni ifodalaydi.
Explicit lockingda transaction invariantga tegishli umumiy rowni FOR UPDATE bilan lock qiladi. Masalan, department rowi barcha doctor schedule o‘zgarishlari uchun serialization point bo‘ladi. Lock tartibi deadlockni kamaytirish uchun bir xil bo‘ladi.
Advisory lock mantiqiy resource key bo‘yicha ishlatilishi mumkin, lekin barcha writerlar uni olishiga intizom bilan rioya qilishi kerak. Aks holda constraint yo‘q.
Testlash
Oddiy bir sessionli test write skewni topmaydi. Ikki connection barrier bilan bir xil snapshotda o‘qitilib, update’lar commit oldidan to‘xtatiladi. Yakuniy invariant va qaysi transaction abort bo‘lgani tekshiriladi.
Production monitoring serialization failure va retry sonini kuzatadi. Retry limit, backoff va idempotency kerak. Juda ko‘p abort contention yoki transaction scope haddan kengligini ko‘rsatishi mumkin.
Modellashtirish
Invariantni bitta rowga jamlash write conflictni ko‘rinadigan qilishi mumkin, lekin hotspot yaratadi. Sharding yoki partition qoidasi bilan lock donadorligi tanlanadi. “Avval SELECT qilib tekshirdim” database concurrency kafolati emas; tekshiruv va update bir transactionda mos isolation/lock bilan bajariladi.
Write skewni oddiy lost update bilan tenglashtirish noto‘g‘ri. Lost updateda ikki tranzaksiya odatda ayni qiymatni yozadi; write skewda esa ular turli satrlarni o‘zgartirib, birgalikdagi biznes invariantini buzadi. Shu sababli alohida satr bloklari yetarli bo‘lmasligi mumkin.
Bog‘liq tushunchalar
Snapshot isolation, Serializable isolation, MVCC, Lost update, Predicate lock, Exclusion constraint, Advisory lock, Serialization failure