دیتابیس طلایی: تستِ سوییت ۲ برابر سریعتر
خلاصهٔ کاملتر
به گفتهٔ Philippe Gaultier، تیمشون یه تستِ سوییتِ بزرگ و بیشتر به زبان Go دارن که پوششِ خوبی داره، ولی به همون نسبت کندتر هم میشه. تقریباً هر تست به یه دیتابیسِ تر و تمیز نیاز داره و کلی زمانِ CPU صرفِ این میشه که بارها و بارها همون مهاجرتهای SQL از اول اجرا بشن. سالها هزاران مهاجرت روی هم جمع شده و همین اجرای پیدرپی، گلوگاهِ اصلی بود.
نویسنده تأکید میکنه قبل از هر بهینهسازی باید ببینی اصلاً ارزششو داره یا نه. برای همین یه آزمایشِ سرانگشتی کرد: فرض گرفت هر تست از همون اول به یه دیتابیسِ آمادهٔ بهروز دسترسی داره. یه بار بعد از اجرای مهاجرتها یه دیتابیسِ SQLiteِ تمیز رو کپی کرد و کدِ تست رو طوری تغییر داد که بهجای اجرای مهاجرتها فقط همون فایل رو بردار. نتیجه ۷ برابر سریعتر شد — یعنی این بهینهسازی ارزششو داشت.
پیادهسازیِ نهایی هوشمندانهست: هر تست اول چک میکنه که فایلِ «دیتابیس طلایی» وجود داره یا نه. اگه بود، فقط کلونش میکنه و یه کپیِ ایزوله برای خودش میسازه. اگه نبود، همهٔ مهاجرتها رو روی یه فایلِ موقت اجرا میکنه، بعد اون فایل رو با نامی که هشِ SHA256ِ محتوای مهاجرتهاست ذخیره میکنه. این «آدرسدهی بر اساس محتوا» یه خاصیتِ قشنگ داره: با اضافه شدنِ هر مهاجرتِ جدید، هش عوض میشه و خودکار یه دیتابیسِ طلاییِ تازه ساخته میشه، بدونِ هیچ منطقِ باطلسازیِ کش.
چند نکته این کارو درست نگه میداره: مهاجرتها مستقیم روی فایلِ طلایی اجرا نمیشن، بلکه روی یه فایلِ موقت اجرا و بعد به اسمِ نهایی تغییرِ نام داده میشن؛ چون os.Rename اتمیه، هیچ تستی یه فایلِ نیمهکاره نمیبینه. نویسنده میگه کپیِ ساده با cp کافی نیست، چون SQLite فایلهای جانبی مثل WAL و shm داره؛ برای همین از backup API خودِ SQLite استفاده کرده. یه فلگِ کنارگذر هم هست برای تستهایی که واقعاً میخوان مهاجرتها رو تکتک اجرا کنن، و استفاده از دیتابیس طلایی فقط داخلِ تستها با testing.Testing() فعاله، نه در محیطِ production.
نویسنده توضیح میده چرا سراغِ راههای دیگه نرفته: «اسکواش» کردنِ همهٔ مهاجرتها تو یه فایل نیاز به نگهداریِ دستی داره و اونها یه ماتریسِ بزرگ از اسکیماها دارن (۴ موتورِ دیتابیس × چند اپلیکیشن × دو نسخهٔ متنباز و تجاری). اجرای تست داخلِ تراکنش و رولبک هم چون رفتارِ داخل و بیرونِ تراکنش فرق داره، به نظرش خوب نیست. دستاوردِ نهایی برای SQLite ۲.۲ برابر شتاب بود — نه اون ۷ برابرِ نمونهٔ اولیه، ولی به گفتهٔ او بدونِ هیچ هزینهٔ اضافه و با کدی کوتاه. بهترین بخش هم اینه که با هر زبانی کار میکنه.
نکات کلیدی:
- بهجای اجرای دوبارهٔ مهاجرتهای SQL در هر تست، یه بار یه «دیتابیس طلایی» ساخته و در هر تست کلون میشه
- نامِ فایل، هشِ SHA256ِ محتوای مهاجرتهاست؛ با هر مهاجرت جدید خودکار بازساخته میشه (بدونِ باطلسازیِ کش)
- برای درستیِ همزمانی از تغییرِ نامِ اتمیِ os.Rename و برای کپیِ سالمِ SQLite از backup API استفاده شده
- این ترفند فقط داخلِ تستها با testing.Testing() فعاله، نه در production
- نتیجه ۲.۲ برابر شتاب برای SQLite بود و با هر زبانی قابل استفادهست




