قبل
«فروشگاه کند است» را همه میگویند؛ هیچکس نمیداند کدام کوئری و کدام فایل.
بعد
یک سشن ضبط، و بعد یک جمله: این دستور در هر لود چند بار اجرا میشود و از کجا خواسته شده.
«فروشگاه کند است» گزارش خطا نیست. ضبط را شروع میکنید، صفحههایی را که کند به نظر میرسند باز میکنید، و افزونه میگوید کدام دستور چند بار اجرا شده و کدام فایل آن را خواسته است. بیرون از یک سشن عیبیابی، هیچ هوکی روی مسیر درخواست ثبت نمیکند و هیچ کوئری اضافه نمیزند؛ سشن هم خودش منقضی میشود. هفت ایندکس آماده — هر کدام با دلیل و هزینهاش — کش شمارش وضعیت سفارشها و هشدار کوئری کند هم در همین بسته هست.
فروشگاهی که چند سال کار کرده کند میشود، و دلیلش تقریباً همیشه دیتابیس است: جدول postmeta بزرگ شده، options پر از رکورد autoload است که در هر درخواست خوانده میشود، و کدی جایی داخل یک حلقه برای هر محصول یک کوئری جدا میزند. تا وقتی کسی نگاه نکند، هیچکدام از اینها اسم و آدرس ندارند.
ابزارهایی که این را جواب میدهند وجود دارند و همه یک اشکال مشترک دارند: باید روشن باشند تا چیزی ببینند، و روشن بودنشان روی هر کوئری حافظه مصرف میکند. به همین دلیل هشدار «روی سایت زنده اجرا نکنید» دارند، وسط یک بحران روشن میشوند، و بعد از بحران روشن میمانند.
این افزونه برعکس ساخته شده. وردپرس فقط وقتی کوئریها را نگه میدارد که ثابت SAVEQUERIES تعریف شده باشد، و wpdb این ثابت را در هر کوئری میخواند — یعنی باید پیش از اولین کوئری وردپرس تعریف شود، خیلی زودتر از آنکه بدانیم کاربر فعلی کیست. راهحل یک دروازه دو مرحلهای است. زمان بارگذاری افزونه: اگر کوکی سشن توکن معتبری همراه داشته باشد، SAVEQUERIES تعریف میشود و کوئریها فقط در حافظه جمع میشوند. زمان shutdown، که وردپرس بالاخره میداند کاربر کیست: قابلیت manage_options، مالک سشن و اعتبار توکن دوباره بررسی میشود و اگر هر کدام رد شود بافر دور ریخته میشود و هیچ ردیفی نوشته نمیشود. بیرون از سشن، افزونه هیچ هوکی روی مسیر درخواست ثبت نمیکند و هیچ کوئری اضافه نمیزند.
خروجی هم فهرست نیست، تفسیر است. چهارصد ردیف SQL داده است؛ یافته این است: «این دستور در هر بار لود صفحه ۳۱۲ بار اجرا میشود، از class-wc-product.php» بهعلاوه یک راهنمایی مشخص ووکامرسی — مثلاً یکبار پر کردن کش با update_meta_cache() بهجای خواندن متای هر محصول جداگانه. هر یافته درجه اهمیت دارد، تا بدانید اول کدام را دست بگیرید و کدام فعلاً میتواند صبر کند.
چون این افزونه با دیتابیس فروشگاه سروکار دارد، حریم خصوصی جزو طراحی است نه یادداشت پایانی: دستورهایی که به users، usermeta، options و جدولهای سفارش، سشن، کلید API و توکن پرداخت ووکامرس میخورند هرگز عیناً ذخیره نمیشوند. الگوی نرمالشده — که هیچ مقدار واقعی در آن نیست — طبق معمول نگه داشته میشود، گزینه «ذخیره نمونه» پیشفرض خاموش است، و نمونه هیچوقت در پاسخ REST نمیآید چون هیچ صفحهای نمایشش نمیدهد.
قبل
«فروشگاه کند است» را همه میگویند؛ هیچکس نمیداند کدام کوئری و کدام فایل.
بعد
یک سشن ضبط، و بعد یک جمله: این دستور در هر لود چند بار اجرا میشود و از کجا خواسته شده.
قبل
ابزار پروفایل باید روشن بماند تا چیزی ببیند، و روشن بودنش روی هر کوئری حافظه میگیرد.
بعد
بیرون از سشن هیچ هوکی روی مسیر درخواست ثبت نمیشود و هیچ کوئری اضافهای زده نمیشود. سشن هم خودش منقضی میشود.
قبل
خروجی چهارصد ردیف SQL است و تفسیرش با شماست.
بعد
کوئریهای همشکل یک ردیف با شمارنده میشوند، و صفحه یافتهها میگوید کدام ردیف را اول درست کنید.
در زبانه ضبط، مدت را انتخاب کنید — پیشفرض ۳۰ دقیقه و حداکثر ۲۴۰ — و یک برچسب بنویسید، مثلاً «صفحه محصول کند».
در یک تب دیگر همان صفحههایی را باز کنید که کند به نظر میرسند. تا وقتی ضبط باز است، یک نشانگر در نوار بالای پیشخوان دیده میشود.
به این تب برگردید. هر یافته درجه اهمیت، یک جمله به زبان ساده و یک راهنمایی ووکامرسی دارد. سشن هم اگر یادتان برود خودش تمام میشود.
فروشگاههای ووکامرس با چند سال داده · فروشگاههای با هزاران محصول یا سفارش · فروشگاههایی که پیشخوانشان کند شده · تیمهایی که بعد از مهاجرت به HPOS چیزی را از دست دادهاند · توسعهدهندگانی که باید افزونه مقصر را نام ببرند · آژانسهایی که فروشگاه مشتری را نگه میدارند · میزبانهایی که باید نشان بدهند مشکل از سرور نیست · هر کسی که باید «فروشگاه کند است» را تبدیل به یک گزارش خطا کند.
همه چیز داخل خود افزونه است. بدون سرویس ابری، بدون Composer، و بدون هیچ کوئری اضافه وقتی ضبط روشن نیست.
تا وقتی ضبط را شروع نکنید هیچچیز ثبت نمیشود. بیرون از سشن، افزونه هیچ هوکی روی مسیر درخواست ثبت نمیکند و هیچ کوئری اضافه نمیزند. توکن سشن در یک کوکی HttpOnly است، انقضای مطلق دارد، و هیچوقت در پاسخ REST نمیآید.
بهجای چهارصد ردیف، جملهای مثل «این دستور در هر بار لود صفحه ۳۱۲ بار اجرا میشود، از class-wc-product.php» — با درجه اهمیت و یک راهنمایی مخصوص ووکامرس برای الگوهای متا، سفارش و ترم.
وقتی یک الگو در یک بارگذاری صفحه بارها تکرار میشود، همان حلقهای است که برای هر آیتم یک کوئری جدا میزند. افزونه فایل مسئول را از call stack بیرون میکشد و فریمهای خود وردپرس را رد میکند. آستانه تکرار پیشفرض ۵ است و قابل تنظیم.
مقادیر با ? جایگزین میشوند تا کوئریهایی که فقط در شناسه فرق دارند یک ردیف با شمارنده شوند. رشتههای داخل کوتیشن پیش از عددهای خام جایگزین میشوند و عدد داخل شناسه دستنخورده میماند، پس wp_woocommerce_order_items سالم میماند و یک فهرست IN با هر طولی به یک شکل جمع میشود.
اندازه جدولها از information_schema — بدون COUNT(*) که خودش روی جدول بزرگ کند است — وزن رکوردهای autoload با آستانه هشدار، و شمارش رکوردهای یتیم: پستمتا، ترممتا، ترم ریلیشنشیپ، آیتم سفارش، متای آیتم سفارش و سشنهای منقضی. فقط میشمارد؛ داده فروشگاه شما را حذف نمیکند.
بازرس و ایندکسر هر دو بررسی میکنند که فروشگاه سفارشها را در wc_orders نگه میدارد یا هنوز در posts، و بر همان اساس هم میشمارند هم پیشنهاد میدهند.
هفت ایندکس آماده برای جدولهای وردپرس و ووکامرس — از جمله جفت meta_key و meta_value روی postmeta و متای آیتم سفارش، و جفت وضعیت و تاریخ روی جدول HPOS. هر کدام دلیل و هزینه تخمینیاش را پیش از ساخت نشان میدهد و وقتی جدول بزرگ است هشدار میدهد.
هر ایندکسی که ساخته میشود ثبت میشود، و حذفکننده از دست زدن به ایندکسی که خودش نساخته امتناع میکند. ادعای مالکیت پیش از اجرای ALTER TABLE نوشته میشود، تا اگر PHP وسط کار روی جدول بزرگ تایماوت شد، ایندکس بیصاحب نماند.
ووکامرس شمارش سفارشها به تفکیک وضعیت را تقریباً در هر صفحه پیشخوان دوباره حساب میکند. این ماژول آن را کش میکند و با یک شمارنده نسخه باطل میکند، نه با حذف کلیدها — و با هر تغییر سفارش تازه میشود.
یک بررسی ساعتی که وقتی کوئریهای سنگین زیاد میشوند ایمیل میفرستد یا به وبهوک POST میکند — با دوره خاموشی، تا یک هفته کند تبدیل به صد پیام یکسان نشود.
دستورهایی که به users، usermeta، options و جدولهای سفارش، سشن، کلید API و توکن پرداخت ووکامرس میخورند فقط به شکل نرمالشده نگه داشته میشوند، هر چه تنظیمات بگوید. گزینه «ذخیره نمونه» پیشفرض خاموش است، و با فیلتر hd_wcdbp_never_sample_tables میتوانید جدول حساس خودتان را هم اضافه کنید.
بدنه وبهوک وقتی کلید تنظیم شده باشد با HMAC-SHA256 امضا میشود. آدرسهای loopback، link-local، شبکه خصوصی و سرویسهای metadata ابری رد میشوند: نام میزبان پیش از تصمیم resolve میشود و اتصال به همان IP بررسیشده pin میشود. کلید هم از هر پاسخ REST حذف و بهصورت فیلد فقطنوشتنی نمایش داده میشود.
همه در docs/hooks.md با مثال. از جمله hd_wcdbp_snapshot برای دور انداختن یک ضبط، hd_wcdbp_never_sample_tables برای اضافه کردن جدول حساس خودتان، hd_wcdbp_index_recipes برای تعریف ایندکس دلخواه، و hd_wcdbp_is_licensed برای کلون استیجینگ که نباید با سرور تماس بگیرد.
ترجمه کامل fa_IR همراه افزونه است و پیشخوان وقتی is_rtl() باشد admin-rtl.css را بار میکند. SQL و مسیر فایل با dir="ltr" علامت خوردهاند تا در پیشخوان راستبهچپ خوانا بمانند. بدون jQuery — جاوااسکریپت وانیلا ES6، فقط روی صفحه خود افزونه.
| امکان | توضیح | دارد |
|---|---|---|
| ضبط محدود به سشن | توکن ۶۴ کاراکتری در کوکی HttpOnly با انقضای مطلق | |
| دروازه دو مرحلهای SAVEQUERIES | کوکی فقط اجازه جمع شدن در حافظه میدهد؛ قابلیت در shutdown بررسی میشود | |
| بدون هوک روی مسیر درخواست | بیرون از سشن هیچ هوکی ثبت و هیچ کوئری اضافه نمیشود | |
| اثر انگشت کوئری | مقادیر با ? جایگزین میشوند؛ نام جدول و ستون دستنخورده میماند | |
| جمع شدن فهرست IN | یک IN با هر طولی به یک شکل تبدیل میشود | |
| تشخیص الگوی N+1 | با نام فایل مسئول، از روی call stack و بدون فریمهای وردپرس | |
| آستانه کندی قابل تنظیم | پیشفرض ۰.۰۵ ثانیه، با فیلتر hd_wcdbp_slow_threshold | |
| آستانه تکرار قابل تنظیم | پیشفرض ۵ بار در یک بارگذاری صفحه | |
| یافته با درجه اهمیت | زیاد، متوسط یا کم — با یک جمله به زبان ساده | |
| راهنمایی مخصوص ووکامرس | مثلاً update_meta_cache() برای الگوی postmeta | |
| فهرست ضبطها | تازهترین، کندترین، یا همهچیز از یک زمینه | |
| ثبت زمینه هر درخواست | frontend، admin، ajax، rest، cron یا cli | |
| پنجره نگهداری و سقف تعداد | ضبط روی صفحه پربازدید خیلی سریع جمع میشود | |
| سقف تعداد شکل در هر درخواست | صفحهای با بیش از دویست شکل، مشکل بزرگتری دارد | |
| اندازه جدولها از information_schema | بدون COUNT(*) روی جدول بزرگ | |
| وزن رکوردهای autoload | با آستانه هشدار و فهرست بیست گزینه بزرگ | |
| شمارش رکوردهای یتیم | پستمتا، ترممتا، ترم ریلیشنشیپ، آیتم سفارش، متای آیتم و سشن منقضی | |
| آگاهی از HPOS | هم در بازرس، هم در ایندکسر | |
| کش و قفل روی اسکن بازرس | دو ادمین همزمان، یک بار اسکن | |
| هفت ایندکس آماده | postmeta، autoload، متای آیتم سفارش، نوع آیتم، وضعیت و تاریخ HPOS، متای HPOS، انقضای سشن | |
| دلیل و هزینه پیش از ساخت | بهعلاوه هشدار وقتی جدول بزرگ است | |
| ثبت مالکیت پیش از ALTER TABLE | تایماوت PHP ایندکس بیصاحب باقی نمیگذارد | |
| Rollback فقط روی ساختههای افزونه | ایندکس دستی یا از پیش موجود دستنخورده میماند | |
| اعتبارسنجی دوباره فیلدهای رسپی | الگوی سختگیرانه پیش از هر ALTER TABLE | |
| کش شمارش وضعیت سفارشها | همان چیزی که ووکامرس در هر صفحه ادمین دوباره حساب میکند | |
| ابطال با شمارنده نسخه | بهجای حذف کلیدهای کش | |
| هشدار کوئری کند | ایمیل یا وبهوک، با بررسی ساعتی | |
| امضای HMAC-SHA256 روی وبهوک | وقتی کلید تنظیم شده باشد | |
| دوره خاموشی هشدار | یک هفته کند، صد پیام یکسان نمیشود | |
| نگهبان آدرس وبهوک | رد loopback، شبکه خصوصی و metadata ابری، با pin روی IP بررسیشده | |
| جدولهای حساس بدون نمونه | users، usermeta، options و جدولهای سفارش، سشن، کلید API و توکن پرداخت | |
| پاکسازی نشانی ضبطشده | password، pwd، key، token و _wpnonce از کوئریاسترینگ حذف میشوند | |
| حذف افزونه، حذف ایندکسها | uninstall.php همیشه ایندکسهای ساختهشده را برمیدارد |
| مورد | حداقل |
|---|---|
| وردپرس | ۶.۲ به بالا، تستشده تا ۶.۸ |
| PHP | ۸.۰ تا ۸.۳ |
| ووکامرس | لازم است — یافتهها و رسپیهای ایندکس برای جدولهای ووکامرس نوشته شدهاند |
| دیتابیس | MySQL یا MariaDB؛ بازرس اندازه جدولها را از information_schema میخواند |
| دسترسی | manage_options برای شروع سشن و خواندن نتیجه، با فیلتر hd_wcdbp_manage_capability قابل تغییر |
برای فروشگاهی که چند سال کار کرده، کند شده، و کسی نمیداند دقیقاً چرا. اگر هزاران محصول و سفارش دارید و پیشخوان یا صفحه محصول کند شده، این افزونه اسم و آدرس مشکل را میدهد. برای فروشگاهی که تازه راه افتاده و صد محصول دارد حرف زیادی ندارد — مشکل آنجا معمولاً دیتابیس نیست. مخاطب دومش توسعهدهنده یا آژانسی است که باید به مشتری نشان بدهد کدام افزونه یا کدام قالب مقصر است، با یک نام فایل بهجای یک حدس.
دقیقاً برای همین ساخته شده. بیرون از یک سشن عیبیابی، افزونه هیچ هوکی روی مسیر درخواست ثبت نمیکند و هیچ کوئری اضافه نمیزند. در طول سشن، سربارش همان سربار SAVEQUERIES خود وردپرس است و با تمام شدن مهلت خودش قطع میشود. داشتن کوکی سشن هم به کسی اجازه خواندن نتیجه نمیدهد؛ برای آن manage_options لازم است. تنها چیزی که واقعاً دیتابیس شما را تغییر میدهد ایندکسر است، که هرگز خودبهخود اجرا نمیشود: دکمه میزنید، تأیید میکنید، و میتوانید برگردانید.
وقتی ضبط خاموش است، افزونه روی درخواستهای عادی هیچ هوکی ثبت نمیکند؛ بررسی کوکی پیش از هر کوئری برمیگردد و به دیتابیس دست نمیزند. CSS و JS پیشخوان فقط روی صفحه خود افزونه بار میشوند. در طول سشن، ضبط کوئری روی هر کوئری حافظه میگیرد — همان کاری که SAVEQUERIES میکند — و تحلیل اسنپشات در shutdown انجام میشود، نه وسط ساخته شدن صفحه. عدد دقیق سربار به فروشگاه شما بستگی دارد و ما عددی نمیسازیم که روی سایت شما اندازه نگرفتهایم.
هر دو بخش، هر دو فعال. بخش عیبیابی: ضبط سشنی، گروهبندی بر اساس شکل کوئری، تشخیص N+1 با نام فایل مسئول، صفحه یافتهها و بازرس دیتابیس. بخش «درست کردن»: ایندکسر هوشمند با هفت ایندکس آماده و Rollback ایمن، کش شمارش وضعیت سفارشها، و هشدار کوئری کند با ایمیل یا وبهوک امضاشده. یعنی هم میفهمید مشکل کجاست، هم ابزار درست کردنش را دارید.
میتواند بکند، و ما این را پنهان نمیکنیم. ALTER TABLE بسته به نسخه MySQL یا MariaDB و اندازه جدول ممکن است طول بکشد و در آن مدت نوشتن روی همان جدول کند یا مسدود شود. به همین دلیل افزونه پیش از ساخت، اندازه جدول و هزینه تخمینی هر ایندکس را نشان میدهد و وقتی جدول بزرگ است هشدار میدهد، و هرگز خودش شروع نمیکند. توصیه ساده است: ساعت خلوت، با یک بکاپ تازه. اگر PHP وسط کار تایماوت شود ایندکس بیصاحب نمیماند، چون ادعای مالکیت پیش از اجرای دستور نوشته شده است.
هر دو. افزونه بررسی میکند که فروشگاه سفارشها را در wc_orders نگه میدارد یا هنوز در posts، و بر همان اساس هم میشمارد هم ایندکس پیشنهاد میدهد. رسپیها هر دو حالت را پوشش میدهند: جفت meta_key و meta_value روی postmeta و متای آیتم سفارش برای حالت قدیمی، و جفت وضعیت و تاریخ و متای HPOS برای حالت جدید.
برداشته میشوند. uninstall.php همیشه ایندکسهایی را که این افزونه ساخته حذف میکند، چه گزینه «حذف دادهها» روشن باشد چه نباشد. جا گذاشتن تغییر ساختار دیتابیس بعد از رفتن افزونهای که آن را ساخته قابل دفاع نیست — بعداً هیچکس نمیداند آن ایندکس چیست و حذفش امن است یا نه. ایندکسی که خودتان یا افزونه دیگری ساخته باشید دستنخورده میماند.
الگوی نرمالشده کوئری هیچ مقدار واقعی ندارد، پس همیشه امن است. آنچه میتواند مقدار واقعی داشته باشد «نمونه» است، یعنی یک نمونه از دستور همانطور که اجرا شده. دستورهایی که به users، usermeta، options و جدولهای سفارش، سشن، کلید API و توکن پرداخت ووکامرس میخورند هرگز با نمونه ذخیره نمیشوند، هر چه تنظیمات بگوید. خودِ گزینه ذخیره نمونه هم پیشفرض خاموش است، نمونه هیچوقت در پاسخ REST نمیآید چون هیچ صفحهای نمایشش نمیدهد، و نشانی هر ضبط پیش از ذخیره از password، pwd، key، token و _wpnonce پاک میشود.
چون هیچ افزونهای نمیتواند آنها را ببیند. وردپرس در زمان راهاندازی، پیش از آنکه فایل هیچ افزونهای include شود، کوئری اجرا میکند، و SAVEQUERIES باید پیش از آنها تعریف شده باشد. افزونه این را روی صفحه مینویسد بهجای اینکه یک فهرست ناقص را کامل جلوه بدهد. اگر آنها را هم لازم دارید، باید SAVEQUERIES را در wp-config.php تعریف کنید — که روی فروشگاه زنده کار درستی نیست.
افزونه به تصمیم شما دست نمیزند و فقط از آن استفاده میکند. در عوض صریحاً روی صفحه میگوید که در این حالت هر درخواست سایت در حال ضبط است، نه فقط سشن شما — چیزی که معمولاً برای یک فروشگاه زنده مطلوب نیست.
نه. افزونه Autoloader کوچک خودش را دارد و در زمان اجرا هیچ وابستگی بیرونی ندارد، و هیچ دادهای به سرویس ابری فرستاده نمیشود. نه بررسی لایسنس دارد و نه بهروزرسان داخلی؛ تنها آدرس بیرونی که ممکن است به آن وصل شود همان وبهوک هشداری است که خودتان تنظیم میکنید. بهروزرسانیها از راه ژاکت میرسد.
خودتان تصمیم میگیرید. گزینه حذف دادهها در تنظیمات هست و پیشفرض خاموش است؛ اگر روشنش کنید، با حذف افزونه هر دو جدول ضبط و همه تنظیمات پاک میشوند. ایندکسها استثنا هستند و همیشه برداشته میشوند. غیرفعال کردن افزونه هم رویدادهای زمانبندیشده را پاک میکند و سشن باز را میبندد، ولی به داده دست نمیزند.
رفع باگ افزونه، راهنمایی نصب و راهاندازی، و کمک برای خواندن یافتهها و تصمیم گرفتن درباره ایندکسها. بهینهسازی خود فروشگاه، بازنویسی کد افزونههای دیگری که مقصر شناخته میشوند، و مشکلات ناشی از قالب یا افزونههای دیگر خارج از پشتیبانی و با توافق جداگانه است.