آشنایی با WAL و مدیریت تراکنشها
📘 درس اول: آشنایی با WAL و مدیریت تراکنشها
🎯 هدف درس
در این درس با مفهوم Write-Ahead Logging (WAL) و نقش حیاتی آن در مدیریت تراکنشهای پایگاههای داده آشنا میشوید. این درس، پایه و اساس تمام مباحث آینده در مورد پیادهسازی WAL در SQLite، PostgreSQL و SQL Server است.
در پایان این درس، شما قادر خواهید بود:
- مفهوم WAL و دلیل ضرورت آن را به زبان ساده توضیح دهید
- ویژگیهای ACID و نقش WAL در هر کدام را شرح دهید
- ساختار رکوردهای لاگ و مفهوم LSN را درک کنید
- تفاوت عملیات REDO و UNDO را به خوبی توضیح دهید
- جایگاه WAL را در بازیابی پس از خرابی (Crash Recovery) بشناسید
- زمینهی لازم برای مطالعهی پیادهسازی WAL در سه پایگاهداده را داشته باشید
📖 سرفصلهای درس
- مقدمهای بر مدیریت تراکنشها
- چالشهای پایگاههای داده
- معرفی Write-Ahead Logging (WAL)
- اصل اساسی WAL: نوشتن لاگ قبل از داده
- ویژگیهای ACID و نقش WAL
- ساختار رکوردهای لاگ و LSN
- عملیات REDO و UNDO
- نقاط بازرسی (Checkpoint)
- فرایند بازیابی پس از خرابی (Crash Recovery)
- جمعبندی و آمادهسازی برای فصلهای بعدی
۱. مقدمهای بر مدیریت تراکنشها
تراکنش چیست؟
تراکنش (Transaction) به مجموعهای از عملیات روی پایگاهداده گفته میشود که یا همه با موفقیت انجام میشوند یا هیچکدام. برای مثال، انتقال وجه از یک حساب به حساب دیگر شامل دو عملیات است:
- برداشت از حساب مبدأ
- واریز به حساب مقصد
اگر یکی از این عملیاتها با شکست مواجه شود، کل تراکنش باید لغو (Rollback) شود تا پایگاهداده در حالت سازگار باقی بماند.
ویژگیهای یک تراکنش ایدهآل
یک تراکنش ایدهآل باید چهار ویژگی اساسی داشته باشد که به اختصار ACID نامیده میشوند:
| ویژگی | توضیح | مثال |
| Atomicity (اتمی بودن) | تراکنش یا کامل انجام میشود یا هیچکدام | انتقال وجه: یا هر دو عملیات انجام میشود یا هیچکدام |
| Consistency (سازگاری) | دادهها همیشه در حالت معتبر هستند | موجودی حساب نمیتواند منفی شود |
| Isolation (انزوا) | تراکنشها از یکدیگر مستقل هستند | دو تراکنش همزمان روی یک حساب تأثیر متقابل ندارند |
| Durability (دوام) | تراکنشهای موفق هرگز از دست نمیروند | پس از تأیید تراکنش، حتی با قطع برق داده از دست نمیرود |
چرا مدیریت تراکنشها مهم است؟
مدیریت تراکنشها به سه دلیل اصلی اهمیت دارد:
- همروندی (Concurrency): چندین کاربر همزمان به پایگاهداده دسترسی دارند و ممکن است روی دادههای مشترک کار کنند
- خرابیهای سیستمی: قطع برق، خطای نرمافزاری، یا خرابی سختافزاری میتواند در هر لحظه رخ دهد
- سازگاری دادهها: دادهها باید همیشه در حالت معتبر باشند و قوانین کسبوکار را رعایت کنند
۲. چالشهای پایگاههای داده
پایگاههای داده با سه چالش اساسی مواجه هستند که هر کدام نیازمند راهحلی مؤثر هستند:
چالش اول: از دست دادن داده پس از خرابی
فرض کنید یک تراکنش موفقیتآمیز انجام شده و به کاربر اعلام شده که عملیات ذخیره شد. اما ناگهان برق قطع میشود. آیا دادهها واقعاً ذخیره شدهاند؟
مشکل: اگر داده فقط در حافظه (RAM) باشد، با قطع برق از بین میرود. اگر مستقیماً روی دیسک نوشته شود، ممکن است عملیات ناتمام بماند و دادهها خراب شوند.
مثال واقعی: فرض کنید در حال ثبت سفارش در یک فروشگاه اینترنتی هستید. پس از کلیک روی دکمه "ثبت سفارش"، سیستم پیام موفقیت را نشان میدهد. اما یک ثانیه بعد برق قطع میشود. آیا سفارش شما ثبت شده است؟ این دقیقاً همان چالشی است که WAL حل میکند.
چالش دوم: عملکرد پایین در نوشتن مستقیم روی دیسک
نوشتن روی دیسک بسیار کندتر از نوشتن در حافظه است. اگر هر تراکنش بخواهد مستقیماً روی دیسک بنویسد، سیستم بسیار کند میشود.
آمار مقایسه سرعت:
| نوع عملیات | زمان تقریبی | سرعت نسبی |
| نوشتن در حافظه (RAM) | ~ ۱۰۰ نانوثانیه | ۱× (سریعترین) |
| نوشتن در حافظه کش (CPU Cache) | ~ ۱ نانوثانیه | ۱۰۰× سریعتر |
| نوشتن روی دیسک (SSD) | ~ ۰.۱ میلیثانیه | ۱۰۰۰× کندتر |
| نوشتن روی دیسک (HDD) | ~ ۱۰ میلیثانیه | ۱۰۰,۰۰۰× کندتر |
نتیجه: نوشتن مستقیم روی دیسک برای هر تراکنش غیرعملی است و سیستم را به شدت کند میکند.
چالش سوم: مدیریت همروندی
چگونه چندین تراکنش همزمان میتوانند بدون تداخل با یکدیگر روی دادهها کار کنند؟
مشکل کلاسیک: دو تراکنش همزمان میخواهند موجودی یک حساب را بهروز کنند. اگر هر دو مقدار فعلی (۱۰۰) را بخوانند و هر کدام ۱۰ واحد اضافه کنند، موجودی نهایی به جای ۱۲۰، تنها ۱۱۰ میشود. این پدیده "مشکل بهروزرسانی گمشده" نام دارد.
۳. معرفی Write-Ahead Logging (WAL)
Write-Ahead Logging یا به اختصار WAL، یک تکنیک اساسی در مدیریت پایگاههای داده است که هر سه چالش بالا را به شکلی هوشمندانه حل میکند.
تعریف ساده WAL: قبل از اینکه هر تغییری روی دادههای اصلی پایگاهداده اعمال شود، توضیح کامل آن تغییر در یک فایل لاگ (Log File) نوشته میشود.
به عبارت دیگر، لاگ همیشه جلوتر از داده است. این اصل ساده، پایه و اساس تمام پایگاههای داده مدرن است.
تاریخچه WAL
مفهوم WAL اولین بار در دهه ۱۹۷۰ میلادی در سیستمهای مدیریت پایگاهداده اولیه مانند System R شرکت IBM مطرح شد. امروزه تمام پایگاههای داده مدرن از این تکنیک استفاده میکنند.
WAL در یک نگاه
| مرحله | توضیح | محل ذخیره |
| ۱ | تراکنش شروع میشود | - |
| ۲ | نوشتن تغییرات در فایل WAL (لاگ) | دیسک (فایل لاگ) |
| ۳ | اعمال تغییرات روی دادههای اصلی | حافظه (و سپس دیسک) |
| ۴ | تراکنش با موفقیت پایان مییابد | - |
مزایای کلیدی WAL
- دوام (Durability): حتی با خرابی ناگهانی، دادهها از دست نمیروند
- عملکرد بالا: نوشتن ترتیبی در لاگ بسیار سریعتر از نوشتن تصادفی روی دیسک است
- بازیابی آسان: با خواندن لاگ میتوان وضعیت پایگاهداده را بازیابی کرد
- پشتیبانی از همروندی: لاگنویسی به مدیریت همروندی کمک میکند
۴. اصل اساسی WAL: نوشتن لاگ قبل از داده
این اصل ساده اما قدرتمند، قلب تمام پایگاههای داده مدرن است:
"Write-Ahead Logging": هیچ تغییری روی دادههای پایگاهداده اعمال نمیشود مگر اینکه قبلاً در لاگ ثبت شده باشد.
چرا این اصل مهم است؟
سناریو ۱: خرابی قبل از نوشتن روی دیسک
| مرحله | وضعیت |
| ۱. تغییرات در لاگ نوشته میشوند | ✅ انجام شد |
| ۲. خرابی رخ میدهد | 💥 برق قطع شد |
| ۳. پس از بازیابی، سیستم لاگ را میخواند | 📖 خواندن لاگ |
| ۴. تغییرات دوباره اجرا (REDO) میشوند | 🔄 اعمال مجدد |
| ۵. دادهها بازیابی میشوند | ✅ هیچ دادهای از دست نمیرود |
سناریو ۲: خرابی در حین نوشتن روی دیسک
| مرحله | وضعیت |
| ۱. تغییرات در لاگ نوشته میشوند | ✅ انجام شد |
| ۲. شروع به نوشتن روی دیسک میشود | ⏳ در حال انجام |
| ۳. خرابی رخ میدهد (نیمی از داده نوشته شده) | 💥 قطع برق |
| ۴. پس از بازیابی، سیستم لاگ را بررسی میکند | 📖 بررسی لاگ |
| ۵. تغییرات ناتمام برمیگردند (UNDO) | ↩️ بازگشت به حالت قبل |
| ۶. دادهها سازگار میشوند | ✅ دادهها هرگز ناسازگار نمیشوند |
مثال عملی کامل
فرض کنید میخواهید موجودی حساب کاربری را از ۱۰۰ به ۱۵۰ تغییر دهید:
| ❌ روش غلط (بدون WAL) | ✅ روش صحیح (با WAL) |
| ۱. مقدار جدید (۱۵۰) را روی دیسک مینویسیم ۲. اگر در این لحظه برق قطع شود → داده خراب میشود (نمیدانیم مقدار ۱۰۰ بوده یا ۱۵۰) |
۱. در لاگ مینویسیم: "تغییر موجودی حساب A از ۱۰۰ به ۱۵۰" ۲. سپس مقدار جدید را روی دیسک مینویسیم ۳. اگر برق قطع شود → با خواندن لاگ، تغییر را دوباره اعمال میکنیم → داده سالم میماند |
نحوهی کار WAL در سطح فیزیکی
وقتی یک تراکنش شروع میشود، مراحل زیر در سطح فیزیکی رخ میدهد:
- نوشتن در بافر لاگ (Log Buffer): تغییرات ابتدا در یک بافر در حافظه نوشته میشوند
- Flush به دیسک: بافر لاگ روی دیسک نوشته میشود (عملیات
fsync) - نوشتن در بافر داده (Data Buffer): تغییرات در بافر داده اعمال میشوند
- Commit: پس از اطمینان از نوشته شدن لاگ، تراکنش Commit میشود
- نوشتن نهایی روی دیسک: در زمان مناسب، بافر داده روی دیسک نوشته میشود
۵. ویژگیهای ACID و نقش WAL
ACID مخفف چهار ویژگی اساسی تراکنشها است. در این بخش، نقش WAL در تضمین هر یک از این ویژگیها را بررسی میکنیم:
| ویژگی | معنی | نقش WAL | مکانیسم |
| Atomicity (یکپارچگی) | تراکنش یا کامل انجام میشود یا هیچکدام | با UNDO، تراکنشهای ناتمام را برمیگرداند | از "Before Image" در لاگ برای بازگشت استفاده میکند |
| Consistency (سازگاری) | دادهها همیشه در حالت معتبر هستند | با اتمیک بودن تراکنشها، سازگاری تضمین میشود | تراکنشهای ناتمام باعث ناسازگاری نمیشوند |
| Isolation (انزوا) | تراکنشها از یکدیگر مستقل هستند | WAL به قفلگذاری و MVCC کمک میکند | لاگ به شناسایی تراکنشهای همزمان کمک میکند |
| Durability (دوام) | تراکنشهای موفق هرگز از دست نمیروند | با REDO، تغییرات را پس از خرابی بازیابی میکند | از "After Image" در لاگ برای اعمال مجدد استفاده میکند |
تمرکز اصلی WAL: Atomicity و Durability
WAL بهطور مستقیم دو ویژگی اتمی بودن و دوام را تضمین میکند:
- اتمی بودن از طریق UNDO (لغو تغییرات ناتمام) تأمین میشود
- دوام از طریق REDO (اجرای مجدد تغییرات موفق) تأمین میشود
برای درک بهتر، بیایید یک مثال کامل را مرور کنیم:
مثال جامع: انتقال وجه با WAL
فرض کنید تراکنش انتقال وجه از حساب A به حساب B را داریم:
BEGIN TRANSACTION; UPDATE accounts SET balance = balance - 100 WHERE id = 'A'; UPDATE accounts SET balance = balance + 100 WHERE id = 'B'; COMMIT;
مراحل با WAL:
| مرحله | عملیات | نوشته شدن در لاگ |
| ۱ | شروع تراکنش | نوشته میشود: BEGIN TXN-101 |
| ۲ | برداشت از حساب A (۱۰۰ → ۰) | نوشته میشود: UPDATE accounts SET balance=0 WHERE id='A' (Before:100, After:0) |
| ۳ | واریز به حساب B (۵۰ → ۱۵۰) | نوشته میشود: UPDATE accounts SET balance=150 WHERE id='B' (Before:50, After:150) |
| ۴ | تأیید تراکنش | نوشته میشود: COMMIT TXN-101 |
| ۵ | اعمال روی دادهها | اکنون تغییرات روی دیسک اعمال میشوند |
اگر در مرحله ۳ خرابی رخ دهد:
- لاگ شامل
BEGINو اولینUPDATEاست، اماCOMMITرا ندارد - سیستم UNDO را اجرا میکند: موجودی حساب A به ۱۰۰ بازمیگردد
- حساب B دستنخورده باقی میماند
- نتیجه: تراکنش کاملاً لغو شد و دادهها سازگار ماندند
اگر در مرحله ۵ خرابی رخ دهد:
- لاگ شامل
COMMITاست، اما تغییرات روی دیسک نوشته نشدهاند - سیستم REDO را اجرا میکند: هر دو UPDATE را دوباره اعمال میکند
- نتیجه: هیچ دادهای از دست نمیرود
۶. ساختار رکوردهای لاگ و LSN
هر رکورد در فایل WAL شامل اطلاعات زیر است:
| ساختار کامل یک رکورد لاگ | |
| LSN | شماره ترتیبی لاگ (مثلاً ۱۰۰۱) - یکتا و افزایشی |
| Transaction ID | شناسه یکتای تراکنش (مثلاً TXN-2026-001) |
| Operation | نوع عملیات: INSERT / UPDATE / DELETE / BEGIN / COMMIT / ABORT |
| Table | نام جدول (مثلاً users, orders, products) |
| Row ID | شناسه ردیف (Primary Key یا ردیفشمار) |
| Before Image | مقدار کامل قبلی (برای UNDO) - شامل تمام ستونها |
| After Image | مقدار کامل جدید (برای REDO) - شامل تمام ستونها |
| Timestamp | زمان دقیق انجام عملیات (با دقت میلیثانیه) |
| Checksum | مجموع بررسی برای اطمینان از صحت داده |
LSN چیست و چرا مهم است؟
LSN (Log Sequence Number) یک شماره ترتیبی منحصربهفرد است که به هر رکورد لاگ اختصاص داده میشود. این شماره:
- ترتیب وقوع رویدادها را بهطور دقیق مشخص میکند
- به سیستم اجازه میدهد بداند آخرین لاگ نوشتهشده کدام است
- در بازیابی، مشخص میکند از کجا شروع به REDO یا UNDO کند
- امکان مقایسه و همگامسازی بین سیستمهای مختلف را فراهم میکند
مثال کامل از یک رکورد لاگ
{
"LSN": 1001,
"TransactionID": "TXN-2026-001",
"Operation": "UPDATE",
"Table": "users",
"RowID": 42,
"Before": {
"id": 42,
"username": "ali_reza",
"email": "ali@example.com",
"balance": 100,
"status": "active",
"updated_at": "2026-07-06T14:25:10"
},
"After": {
"id": 42,
"username": "ali_reza",
"email": "ali@example.com",
"balance": 150,
"status": "active",
"updated_at": "2026-07-06T14:30:25"
},
"Timestamp": "2026-07-06 14:30:25.123",
"Checksum": "a3f5c8d9e2b1"
}
انواع رکوردهای لاگ
| نوع رکورد | توضیح | مثال |
| BEGIN | شروع یک تراکنش جدید | BEGIN TXN-101 |
| UPDATE | بهروزرسانی یک رکورد | UPDATE users SET balance=150 WHERE id=42 |
| INSERT | درج یک رکورد جدید | INSERT INTO users VALUES (...) |
| DELETE | حذف یک رکورد | DELETE FROM users WHERE id=42 |
| COMMIT | تأیید و پایان تراکنش | COMMIT TXN-101 |
| ABORT | لغو تراکنش | ABORT TXN-101 |
| CHECKPOINT | نقطه بازرسی | CHECKPOINT LSN=950 |
۷. عملیات REDO و UNDO
دو عملیات اصلی در بازیابی با WAL:
REDO (اجرای مجدد) - جزئیات کامل
تعریف: REDO به فرایند اعمال مجدد تغییرات یک تراکنش از روی لاگ گفته میشود.
وقتی استفاده میشود:
- تراکنش موفق بوده (
COMMITدر لاگ وجود دارد) - اما تغییرات روی دیسک نوشته نشدهاند
- یا بهطور کامل نوشته نشدهاند
مراحل اجرای REDO:
| مرحله | توضیح |
| ۱ | سیستم آخرین نقطهی امن (Checkpoint) را پیدا میکند |
| ۲ | از Checkpoint شروع به خواندن لاگ به جلو میکند |
| ۳ | برای هر رکورد، اگر متعلق به تراکنش موفق باشد |
| ۴ | از "After Image" استفاده کرده و تغییر را اعمال میکند |
| ۵ | پس از رسیدن به آخر لاگ، همه تغییرات اعمال شدهاند |
مثال REDO:
لاگ بعد از Checkpoint: LSN 951: UPDATE accounts SET balance=200 WHERE id=1 (After:200) LSN 952: UPDATE accounts SET balance=300 WHERE id=2 (After:300) LSN 953: COMMIT TXN-102 سیستم REDO را اجرا میکند: → اعمال LSN 951: حساب 1 → ۲۰۰ → اعمال LSN 952: حساب 2 → ۳۰۰ → نتیجه: دادهها بهروز شدند
UNDO (بازگشت به عقب) - جزئیات کامل
تعریف: UNDO به فرایند برگرداندن تغییرات یک تراکنش با استفاده از لاگ گفته میشود.
وقتی استفاده میشود:
- تراکنش ناموفق بوده یا نیمهتمام مانده است
COMMITدر لاگ وجود ندارد- یا کاربر بهصورت دستی تراکنش را لغو کرده است
مراحل اجرای UNDO:
| مرحله | توضیح |
| ۱ | سیستم از آخرین رکورد لاگ شروع به خواندن به عقب میکند |
| ۲ | برای هر رکورد، اگر متعلق به تراکنش ناتمام باشد |
| ۳ | از "Before Image" استفاده کرده و تغییر را برمیگرداند |
| ۴ | تا رسیدن به BEGIN آن تراکنش ادامه مییابد |
| ۵ | دادهها به حالت قبل از تراکنش بازمیگردند |
مثال UNDO:
لاگ (از آخر به اول): LSN 953: BEGIN TXN-103 LSN 952: UPDATE accounts SET balance=200 WHERE id=1 (Before:100) LSN 951: UPDATE accounts SET balance=300 WHERE id=2 (Before:250) LSN 950: BEGIN TXN-103 سیستم UNDO را اجرا میکند: → خواندن LSN 952: حساب 1 ← ۱۰۰ (برگشت) → خواندن LSN 951: حساب 2 ← ۲۵۰ (برگشت) → نتیجه: دادهها به حالت قبل بازگشتند
مقایسه جامع REDO و UNDO
| ویژگی | REDO | UNDO |
| چه زمانی | پس از خرابی برای تراکنشهای موفق | برای تراکنشهای ناتمام یا لغو شده |
| از کجا میخواند | از Checkpoint به جلو (ترتیبی) | از آخر به اول (برعکس) |
| از چه دادهای استفاده میکند | After Image | Before Image |
| نتیجه | اعمال مجدد تغییرات | برگرداندن تغییرات |
| چه تراکنشهایی تحت تأثیر قرار میگیرند | تراکنشهای با COMMIT | تراکنشهای بدون COMMIT |
| آیا میتواند چند بار اجرا شود؟ | بله (Idempotent - اجرای مجدد ضرری ندارد) | بله (Idempotent - اجرای مجدد ضرری ندارد) |
۸. نقاط بازرسی (Checkpoint)
نقطهی بازرسی (Checkpoint) نقطهای در زمان است که تمام تغییرات نوشتهشده در لاگ، روی دیسک اعمال شدهاند.
چرا Checkpoint مهم است؟
بدون Checkpoint، برای بازیابی باید تمام لاگ را از ابتدا تا انتها بخوانیم که بسیار زمانبر است. با Checkpoint:
- فقط لاگهای بعد از آخرین Checkpoint نیاز به پردازش دارند
- سرعت بازیابی به شدت افزایش مییابد
- لاگهای قدیمی میتوانند حذف شوند (صرفهجویی در فضا)
تصویر مفهومی Checkpoint
زمان ──────────────────────────────────────────────────────────────────►
[شروع] -- [لاگها] -- [CHECKPOINT 1] -- [لاگها] -- [CHECKPOINT 2] -- [لاگها] -- [خرابی]
↑ ↑ ↑
│ │ │
نیازی به خواندن نیست این بخش برای بازیابی بازیابی از اینجا
(قبل از Checkpoint 1) (بین CP1 و CP2) شروع میشود
فرایند کامل Checkpoint
| مرحله | توضیح |
| ۱ | سیستم تمام تغییرات جاری در حافظه (بافر داده) را شناسایی میکند |
| ۲ | تمام بافرهای داده "کثیف" (Dirty Buffers) روی دیسک نوشته میشوند |
| ۳ | یک رکورد Checkpoint در لاگ ثبت میشود با LSN فعلی |
| ۴ | لاگهای قدیمیتر از Checkpoint میتوانند حذف یا بایگانی شوند |
| ۵ | در صورت خرابی، بازیابی از آخرین Checkpoint شروع میشود |
انواع Checkpoint
| نوع | توضیح | مزایا | معایب |
| Full Checkpoint | تمام بافرهای کثیف روی دیسک نوشته میشوند | ساده و کامل | کند و مصرفکننده منابع |
| Fuzzy Checkpoint | فقط بخشی از بافرهای کثیف نوشته میشوند | سریعتر و کارآمدتر | پیچیدگی بیشتر در بازیابی |
| Automatic | توسط خود سیستم در بازههای زمانی مشخص انجام میشود | بدون نیاز به دخالت کاربر | کنترل کمتر |
| Manual | توسط مدیر پایگاهداده دستی اجرا میشود | کنترل کامل | نیاز به تخصص و برنامهریزی |
تأثیر Checkpoint بر عملکرد
- Checkpoint مکرر: ↑ سرعت بازیابی، ↓ عملکرد عادی (چون نوشتن روی دیسک زیاد میشود)
- Checkpoint با فاصله: ↓ سرعت بازیابی، ↑ عملکرد عادی (نوشتن کمتر روی دیسک)
تنظیم بهینه: تعادل بین سرعت بازیابی و عملکرد عادی با توجه به نیاز سیستم
۹. فرایند بازیابی پس از خرابی (Crash Recovery)
وقتی پایگاهداده پس از یک خرابی دوباره راهاندازی میشود، سه مرحله اصلی را طی میکند:
مرحله ۱: تحلیل (Analysis)
| جزئیات مرحله تحلیل | |
| کار انجام شده | - خواندن آخرین Checkpoint از لاگ - مشخص کردن تراکنشهای موفق (با COMMIT) و ناتمام (بدون COMMIT) - تعیین اولین LSN که نیاز به REDO دارد - شناسایی آخرین LSN برای UNDO |
| خروجی | لیست تراکنشهای موفق و ناتمام + محدوده لاگ برای پردازش |
مرحله ۲: REDO (اجرای مجدد)
| جزئیات مرحله REDO | |
| کار انجام شده | - از اولین LSN شناساییشده در مرحله تحلیل شروع میشود - تا آخرین LSN لاگ ادامه مییابد - برای هر رکورد متعلق به تراکنش موفق، REDO اجرا میشود - از After Image برای اعمال مجدد استفاده میشود |
| نکته مهم | REDO حتی روی تراکنشهایی که بعداً UNDO میشوند نیز اجرا میشود (برای سادگی) |
| خروجی | دادهها به وضعیت زمان خرابی بازگردانده میشوند |
مرحله ۳: UNDO (بازگشت)
| جزئیات مرحله UNDO | |
| کار انجام شده | - از آخرین LSN به سمت عقب حرکت میکند - برای هر رکورد متعلق به تراکنش ناتمام، UNDO اجرا میشود - از Before Image برای برگرداندن تغییرات استفاده میشود - تا رسیدن به BEGIN هر تراکنش ادامه مییابد |
| نکته مهم | UNDO فقط روی تراکنشهای ناتمام اجرا میشود |
| خروجی | دادهها به حالت سازگار نهایی بازمیگردند |
مثال کامل سناریوی بازیابی
فرض کنید در زمان خرابی، سه تراکنش در حال اجرا بودهاند:
| تراکنش | وضعیت در زمان خرابی | اقدام بازیابی | دلیل |
| T1 | موفق و Commit شده | REDO (اعمال مجدد) | COMMIT در لاگ وجود دارد، ممکن است روی دیسک نرفته باشد |
| T2 | در حال اجرا (نیمهتمام) | UNDO (بازگشت) | COMMIT در لاگ وجود ندارد، باید لغو شود |
| T3 | موفق و Commit شده | REDO (اعمال مجدد) | COMMIT در لاگ وجود دارد |
نتیجه نهایی پس از بازیابی:
- ✅ تغییرات T1 اعمال میشوند
- ✅ تغییرات T3 اعمال میشوند
- ❌ تغییرات T2 کاملاً لغو میشوند
- 📊 پایگاهداده به حالت سازگار بازمیگردد
نمودار کامل فرایند بازیابی
┌─────────────────────────────────────────────────────────────────────┐
│ خرابی رخ میدهد │
└─────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ مرحله ۱: تحلیل (Analysis) │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ • خواندن آخرین Checkpoint (LSN=950) │ │
│ │ • شناسایی تراکنشهای موفق: T1, T3 │ │
│ │ • شناسایی تراکنشهای ناتمام: T2 │ │
│ │ • تعیین محدوده REDO: از LSN 951 تا پایان │ │
│ └─────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ مرحله ۲: REDO (اجرای مجدد) │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ • از LSN 951 شروع میشود │ │
│ │ • اعمال مجدد LSN 951: UPDATE account 1 → 200 (T1) │ │
│ │ • اعمال مجدد LSN 952: UPDATE account 2 → 300 (T3) │ │
│ │ • اعمال مجدد LSN 953: UPDATE account 1 → 250 (T2) │ │
│ │ • رسیدن به پایان لاگ │ │
│ └─────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ مرحله ۳: UNDO (بازگشت) │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ • از آخر لاگ به عقب حرکت میکند │ │
│ │ • برگرداندن LSN 953: account 1 ← 200 (UNDO T2) │ │
│ │ • ادامه تا BEGIN T2 │ │
│ │ • تراکنش T2 کامل لغو شد │ │
│ └─────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ ✅ پایگاهداده بازیابی شد │
│ نتیجه: تغییرات T1 و T3 اعمال شده، تغییرات T2 لغو شده │
└─────────────────────────────────────────────────────────────────────┘
۱۰. جمعبندی و آمادهسازی برای فصلهای بعدی
آنچه در این درس آموختیم:
| # | مفهوم | توضیح |
| ✅ | WAL | یک تکنیک اساسی برای تضمین دوام و یکپارچگی دادهها است |
| ✅ | نوشتن لاگ قبل از داده | اصل اساسی WAL که از خرابیهای سیستمی محافظت میکند |
| ✅ | LSN | شمارهی ترتیبی برای ردیابی ترتیب عملیاتها و بازیابی |
| ✅ | REDO | تغییرات موفق را دوباره اعمال میکند (با After Image) |
| ✅ | UNDO | تغییرات ناتمام را برمیگرداند (با Before Image) |
| ✅ | Checkpoint | فرایند بازیابی را سریعتر میکند و لاگ را مدیریت میکند |
| ✅ | بازیابی سه مرحلهای | تحلیل → REDO → UNDO |
مفاهیم کلیدی که باید به خاطر بسپارید:
- WAL = امنیت + عملکرد: با نوشتن ترتیبی در لاگ، هم سرعت بالا میرود و هم امنیت دادهها تضمین میشود
- لاگ همیشه جلوتر است: هیچ تغییری روی دادهها اعمال نمیشود مگر اینکه در لاگ ثبت شده باشد
- REDO برای موفقها، UNDO برای ناتمامها: تراکنشهای موفق REDO و تراکنشهای ناتمام UNDO میشوند
- Checkpoint کلید سرعت: با Checkpoint منظم، بازیابی سریعتر و مدیریت لاگ آسانتر میشود
در فصلهای بعدی خواهیم آموخت:
| فصل | پایگاهداده | موضوع اصلی | ارتباط با WAL |
| فصل ۲ | SQLite | فعالسازی WAL، ساختار فایلهای -wal و -shm |
پیادهسازی عملی WAL در یک دیتابیس سبک |
| فصل ۳ | SQLite | بررسی عملکرد و تأثیر بر Django | WAL در دنیای واقعی و فریمورکها |
| فصل ۴ | PostgreSQL | معماری WAL، فایلهای لاگ و Replication | WAL در یک دیتابیس سنگین و حرفهای |
| فصل ۵ | PostgreSQL | Checkpoint و بازیابی پیشرفته | مدیریت پیشرفته WAL در PostgreSQL |
| فصل ۶ | SQL Server | Transaction Log و Recovery Models | معماری لاگ در SQL Server |
| فصل ۷ | SQL Server | Backup و بازیابی اطلاعات | استفاده از WAL در پشتیبانگیری |
| فصل ۸ | مقایسه | تفاوتهای پیادهسازی WAL در سه پایگاهداده | کدام رویکرد برای چه پروژهای مناسب است |
| فصل ۹ | بهترین شیوهها | استفادهی بهینه از WAL در پروژههای واقعی | نکات عملی و ترفندهای حرفهای |
📝 سوالات مروری
برای اطمینان از درک مطلب، به این سوالات پاسخ دهید:
- چرا باید لاگ قبل از داده نوشته شود؟ سه دلیل اصلی را توضیح دهید
- تفاوت REDO و UNDO چیست؟ هر کدام چه زمانی استفاده میشوند؟
- Checkpoint چه تأثیری بر سرعت بازیابی دارد؟ چه نوع Checkpointهایی وجود دارند؟
- اگر تراکنشی Commit شده باشد اما روی دیسک نوشته نشده باشد، چه اتفاقی میافتد؟
- LSN چه کاربردی دارد و چرا مهم است؟
- سه مرحله بازیابی پس از خرابی را به ترتیب نام ببرید و توضیح دهید
- تفاوت "Before Image" و "After Image" چیست و هر کدام در کدام عملیات استفاده میشود؟
- چرا WAL به بهبود عملکرد کمک میکند؟
پاسخهای خلاصه برای خودآزمایی:
🔍 پاسخ سوالات (برای بررسی)
- لاگ قبل از داده: ۱) تضمین دوام داده ۲) بازیابی پس از خرابی ۳) امکان UNDO و REDO
- REDO: برای تراکنشهای موفق و COMMIT شده، UNDO: برای تراکنشهای ناتمام
- Checkpoint: باعث میشود فقط لاگهای بعد از آخرین Checkpoint پردازش شوند
- سیستم REDO را اجرا میکند و تغییرات را از روی لاگ اعمال میکند
- LSN: شماره ترتیبی لاگ برای ردیابی ترتیب و بازیابی
- مراحل بازیابی: ۱) تحلیل ۲) REDO ۳) UNDO
- Before Image: مقدار قبلی (برای UNDO)، After Image: مقدار جدید (برای REDO)
- WAL و عملکرد: نوشتن ترتیبی در لاگ بسیار سریعتر از نوشتن تصادفی روی دیسک است
🔗 منابع برای مطالعه بیشتر
- 📘 SQLite WAL Documentation - مستندات رسمی
- 📘 PostgreSQL WAL Internals - مستندات رسمی
- 📘 SQL Server Transaction Log Architecture - مستندات رسمی
- 📘 Wikipedia - Write-Ahead Logging
- 📘 PostgreSQL Continuous Archiving and Point-in-Time Recovery
🎯 در درس بعدی:
پیادهسازی عملی WAL در SQLite را آغاز میکنیم.
فعالسازی WAL، بررسی فایلهای -wal و -shm، و تأثیر بر عملکرد
✅ پایان درس اول: آشنایی با WAL و مدیریت تراکنشها