سطوح ایزولهسازی دیتابیس اون چیزی که فکر میکنی نیستن
خلاصهٔ کاملتر
نویسنده با یه باگ واقعی شروع میکنه: یه اپ زمانبندی بیمارستان که باید همیشه حداقل یه پزشک آنکال داشته باشه. دو پزشک همزمان دکمهٔ خروج رو میزنن، هر دو تعداد پزشکهای آنکال رو دو تا میبینن، هر دو فکر میکنن رفتنشون امنه و هر دو خارج میشن. حالا صفر پزشک آنکال مونده و دیتابیس بدون هیچ خطایی هر دو تغییر رو ثبت کرده. به گفتهٔ نویسنده، ایزولهسازی دقیقاً همینه: اینکه یه تراکنش وقتی تراکنش دیگه در حال اجراست، چی رو مجازه ببینه.
استاندارد SQL چهار سطح ایزولهسازی تعریف میکنه که سهتاش پرکاربردن. تو Read Committed تراکنش فقط دادهٔ commitشده رو میبینه. تو Repeatable Read اگه یه ردیف رو دو بار بخونی همون جواب رو میگیری، چون دیتابیس یه snapshot از داده نگه میداره که پایهٔ MVCCه. Serializable هم قویترین سطحه و تضمین میکنه نتیجه انگار تراکنشها پشت سر هم اجرا شدن. نویسنده میگه یه محور مهم دیگه هم هست: خوشبینانه در برابر بدبینانه.
نکتهٔ اصلی مقاله اینه که این اسمها گولزنندهان. استاندارد SQL سال ۱۹۹۲ سطوح رو با «چه اتفاق بدی رو جلوگیری میکنن» تعریف کرد، نه با نحوهٔ پیادهسازی. ولی یه مقالهٔ نقد معروف سال ۱۹۹۵ نشون داد این تعریف چند باگ مهم رو جا انداخته؛ مثل lost update و write skew. همون باگ بیمارستان write skewه: دو تراکنش یه چیز رو میخونن، هرکدوم روی یه ردیف متفاوت مینویسن، پس هیچ قفلی گیر نمیکنه و قانون میشکنه. جالبه که Snapshot Isolation اصلاً تو جدول استاندارد جا نمیگیره.
بعد نویسنده دیتابیسها رو یکییکی بررسی میکنه. PostgreSQL از همه صادقتره و تو مستنداتش میگه Repeatable Readش در واقع همون Snapshot Isolationه، پس هنوز به write skew آسیبپذیره. Serializableش با روش SSI کار میکنه که خوشبینانهست: میذاره تراکنش کامل اجرا بشه و آخرش اگه الگوی خطرناکی ببینه، با خطای SQLSTATE 40001 یکیشون رو میکشه. اگه اپت این خطا رو نگیره و دوباره تلاش نکنه، عملاً تراکنشهات تصادفی fail میشن.
MySQL داستان عجیبتری داره. دیفالتش Repeatable Readه و تو این سطح InnoDB همزمان دو تا سیستم کنترل همروندی رو اجرا میکنه: SELECT ساده از snapshot میخونه، ولی خوندنهای قفلدار مثل FOR UPDATE و دستورهای نوشتن، دادهٔ زندهٔ فعلی رو میخونن و قفل میکنن. یعنی تو یه تراکنش، یه جور خوندن گذشته رو میبینه و یه جور دیگه حال رو. نویسنده میگه اینجا اینکه write skew بهت میخوره یا نه، بستگی داره به اینکه چطور خوندی. Serializableش هم برعکس PostgreSQL بدبینانهست و همهچی رو با قفل بلاک میکنه.
به گفتهٔ نویسنده، Oracle فقط دو سطح داره: Read Committed و Serializable؛ اگه Repeatable Read بذاری مستقیم خطا میده. جمعبندی مقاله اینه که یه اسم مثل Serializable یه قرارداد ثابت مثل کد وضعیت HTTP نیست؛ هر فروشنده هرچی داشته رو ساخته و بعد اسم استاندارد رو روش گذاشته. برای همین موقع مهاجرت بین دیتابیسها، همین اسمهای بهظاهر مشترک میتونن تیمها رو بدجوری گیر بندازن.
نکات کلیدی:
- سطوح ایزولهسازی با اینکه اسم استاندارد دارن، تو هر دیتابیس رفتار متفاوتی دارن.
- write skew یعنی دو تراکنش روی ردیفهای متفاوت بنویسن و یه قانون مشترک رو بشکنن، بدون اینکه قفلی گیر کنه.
- Repeatable Read تو PostgreSQL و MySQL در واقع Snapshot Isolationه و جلوی write skew رو نمیگیره.
- Serializable تو PostgreSQL خوشبینانهست و تراکنش رو آخر کار میکشه؛ تو MySQL بدبینانهست و با قفل بلاک میکنه.
- موقع مهاجرت بین دیتابیسها به تفاوت واقعی این سطوح دقت کن، نه فقط اسمشون.




