تحسين الاستعلامات إلى قاعدة البيانات هو شيء أساسي حينما يتعلق الأمر بتطوير المواقع الإلكترونية والبرمجة بشكل عام، خصوصا إذا كان المشروع الذي تعمل عليه يستقبل الزيارات بنسبة عالية، هنا يجب علينا تقليل الاستعلامات على قاعدة البيانات لكيلا يتم استنزاف موارد الخادم.
في حالة العكس، وإذا كان الكود غير محسن والاستعلامات تتم بشكل مكثف، يمكن أن يؤدي هذا إلى بطء تصفح الموقع أو توقفه نهائيا عن الاستجابة.
تحسين الاستعلامات على قاعدة البيانات
في ووردبريس لدينا عدة وسائل للتعامل مع قواعد البيانات لكن في غالب الحالات نستخدم WP_Query
.
WP_Query هو عبارة عن كلاس يسمح لنا بجلب بيانات الصفحاتـ المقالات وأنواع المقالات المخصصة. افتراضيا، يتم تنفيذ 5 استعلامات تتضمن على سبيل المثال التخزين المؤقت لبيانات الميتا، عداد التصفح … الخ
دائما عند قيامك باستعلام عن طريق WP_Query خد بعين الاعتبار البارامترات التالية:
$args = [
'no_found_rows' => true,
'update_post_meta_cache' => false,
'update_post_term_cache' => false,
'posts_per_page' => 5
];
$the_query = new WP_Query( $args );
no_found_rows
يستعمل لعمل تصفح للبيانات العائدة من من WP_Query. في حالة عدم استخدامك للتصفح في الإستعلام الذي تقوم به، ببساطة قم بإعطائه القيمة true.
update_post_term_cache
هذا البارمتر اعطيه القيمة false
لكيلا يتم تحديث التخزين المؤقت للتصنيفات والوسوم والتصنيفات المخصصة، هكذا توفر عليك استعلام آخر (فقط استخدمه إذا كنت لا تحتاج ترتيب المواضيع حسب التصنيف (taxonomy)!).
update_post_term_cache
هو نفس ما ذكرناه سابقا لكن هذه المرة يتعلق بالتخزين المؤقت الخاص بالخصائص الإضافية ( post meta)، ففي حالة عدم إدراج خصائص إضافية في الاستعلام يمكنك إعطائها القيمة false
.
posts_per_page
هذا البرامتر يمكن من خلاله تحديد عدد المواضيع التي سيتم جلبها من قاعدة البيانات، ولجب كل المواضيع هناك من يضع 1- وهذا قد لا يكون مناسب إذا كان الموقع الذي تعمل عليه يتوفر على آلاف المقالات فمن الأفضل تحديد عدد المقالات الواجب جلبها لتخفيف العبء على الخادم، على سبيل المثال 'posts_per_page' => 500
.
من الأشياء التي يمكن عملها أيضا تحديد معلومات المقالة التي نحتاجها في الاستعلام، فعلى سبيل المثال إذا كنا نحتاج فقط المعرف الوحيد والعنوان، الكود سيكون على هذا الشكل:
add_filter( 'posts_fields', 'posts_fields_custom_variable', 10, 2 );
function posts_fields_custom_variable( $fields, $query ) {
global $wpdb;
// Only if our custom variable is not false.
if ( $query->get( 'limit_fields' ) ) {
$fields = "$wpdb->posts.ID, $wpdb->posts.post_title";
}
return $fields;
}
$args = [
'post_type' => 'post',
'no_found_rows' => true,
'update_post_meta_cache' => false,
'update_post_term_cache' => false,
'posts_per_page' => 5,
// Our custom variable.
'limit_fields' => true,
];
$the_query = new WP_Query( $args );
إذا كنا سنحتاج المعرف الوحيد فقط نستعمل البارمتر fields على هذا الشكل
$args = [
'fields' => 'ids',
];
في الحلقة Loop الأساسية للووردبريس، يتم استعمال الوظيفة update_post_thumbnail_cache()
للحصول على معلومات الصور المصغرة لكل مقالات ال Loop مرة واحدة فقط. تخزن تلك المعلومات في الكاش وتستخدم بعدها لعرض الصور المصغرة عندما يتم استدعاؤها، وبهذا يتم تجنب عمل استعلام إضافي لكل صورة مصغرة في ال Loop.
لكن للأسف هذه الوظيفة لا تستخدم افتراضيا في الاستعلامات المخصصة عبر WP_Query، ويمكننا إضافتها على هذا الشكل
<?php
$args = array(
'post_type' => 'post',
'post_per_page' => 5,
'no_found_rows' => true,
'update_post_term_cache' => false,
'suppress_filters' => true,
);
$the_query= new WP_Query( $args );
if( $the_query->have_posts() ) {
update_post_thumbnail_cache( $the_query);
echo '<ul>';
while( $the_query->have_posts() ) {
$the_query->the_post();
?>
<li>
<h3><?php the_title(); ?></h3>
<?php the_post_thumbnail( 'thumbnail' ); ?>
</li>
<?php
}
wp_reset_postdata();
echo '</ul>';
}
لكن بدل وضع update_post_thumbnail_cache()
داخل كل استعلام مخصص، يمكننا إضافة بارامتر مخصص نعطيه القيمة true في كل الاستعلامات التي ستحتوي على صور مصغرة.
add_filter( 'the_posts', 'sb_prime_post_thumbnails_cache', 10, 2 );
function sb_prime_post_thumbnails_cache( $posts, $query ) {
if( ! $query->is_main_query() && $query->get( 'sb_upadate_post_thumbnail_cache' ) ) {
update_post_thumbnail_cache( $query );
}
return $posts;
}
نستخدمه هكذا
$args = [
// Our custom parameter
sb_upadate_post_thumbnail_cache' =>; true,
];
$latest_news = new WP_Query( $args );
علينا أن نعلم أيضا أن الوظيفة get_posts()
تستخدم داخليا WP_Query
وتحدد بعض البارامترات بقيمة مناسبة ك 'no_found_rows' => true
، وكذلك تضع 'suppress_filters' => true
وهذا يستبعد نتائج الاستعلام من نظام التخزين المؤقت الخاص بووردبريس، لهذا لا تنسى تمريره بالقيمة false في حالة استعمالك ل get_posts()
ونفس الأمر مع wp_get_recent_posts()
و get_children()
.
ولكي تكون استعلاماتنا أسرع يجب علينا تجنب قدر الإمكان البحث في جداول متعددة، على سبيل المثال استعلامات حسب تصنيفات (taxonomy) متعددة، استعلامات حسب خصائص إضافة (post meta) متعددة وكذلك الإبتعاد عن البارامترات من نوع __in و not_in كسبيل المثال category__in
، category__not_in
، post__not_in
، tag__not_in
… الخ
وفي حالة ضرورة استعمالها من الواجب عمل تخزين مؤقت للاستعلامات.
التخزين المؤقت للإستعلامات في ووردبريس
ووردبريس يوفر لنا واجهتين برمجيتين تمكناننا من عمل تخزين مؤقت لاستعلاماتنا، الأولى WP Object Cache والأخرى Transients API.
الفرق بينها هو أن الأولى غير مستمرة (non-persistent) حيث يتم تخزين الاستعلام في الذاكرة العشوائية خلال مدة الاستعلام فقط، إذا أردت أن يتم عمل تخزين مستمر ( persistent caching ) عليك استخدام أحد الحلول ك W3 Total Cache، Memcached Object Cache، Redis Object Cache …
وهذا أفضل مثال للاستخدام WP Object Cache في WP_Query
$result = wp_cache_get( 'my_result' );
if ( false === $result ) {
$args = array(
'post_type' => 'post',
'tax_query' => array(
'relation' => 'OR',
array(
'taxonomy' => 'category',
'field' => 'slug',
'terms' => array( 'quotes' ),
),
array(
'relation' => 'AND',
array(
'taxonomy' => 'post_format',
'field' => 'slug',
'terms' => array( 'post-format-quote' ),
),
array(
'taxonomy' => 'category',
'field' => 'slug',
'terms' => array( 'wisdom' ),
),
),
),
);
$query = new WP_Query( $args );
wp_cache_set( 'my_result', $query );
}
أما Transients API فتقوم بتخزين نتيجة الإستعلام في قاعدة البيانات، بالتحديد في جدول wp_options
عوض تخزينه في الذاكرة، وبهذا يمكننا جلب نتيجة الاستعلام جاهزة في كل مرة وبالتالي تحسين كبير في الآداء وتخفيف العبء على الخادم.
مثال لاستخدام Transients API في WP_Query
$result = get_transient( 'my_result' );
if ( false === $result ) {
$args = array(
'post_type' => 'post',
'tax_query' => array(
'relation' => 'OR',
array(
'taxonomy' => 'category',
'field' => 'slug',
'terms' => array( 'quotes' ),
),
array(
'relation' => 'AND',
array(
'taxonomy' => 'post_format',
'field' => 'slug',
'terms' => array( 'post-format-quote' ),
),
array(
'taxonomy' => 'category',
'field' => 'slug',
'terms' => array( 'wisdom' ),
),
),
),
);
$query = new WP_Query( $args );
set_transient( 'my_result', $query, HOUR_IN_SECONDS );
}
في هذا المثال قمنا بتحديد مدة صلاحية التخزين المؤقت في ساعة من الزمن، ووردبريس يوفر ستة ثوابت لتحديد المدة الزمنية لكن يمكنك استخدام نماذج أخرى من عندك إذا أردت
MINUTE_IN_SECONDS = 60 (seconds)
HOUR_IN_SECONDS = 60 * MINUTE_IN_SECONDS
DAY_IN_SECONDS = 24 * HOUR_IN_SECONDS
WEEK_IN_SECONDS = 7 * DAY_IN_SECONDS
MONTH_IN_SECONDS = 30 * DAY_IN_SECONDS
YEAR_IN_SECONDS = 365 * DAY_IN_SECONDS
بالإضافة إلى عمل تخزين مؤقت لاستعلامات قاعدة البيانات، يمكننا أيضا تخزين الاستعلامات الخارجية، نعم، إذا كان موقعك يستقبل زيارات كثيرة ويعمل استعلامات على خدمات خارجة، فمن الأفضل تخزين تلك الاستعلامات ولو لمدة قصيرة.
على سبيل المثال، هناك زر فايسبوك يعرض عدد الإعجابات لكل تدوينة وفي كل زيارة يتم الاتصال ب API فايسبوك لجلب عدد الإعجابات، في هذه الحالة يمكننا مثلا تخزين النتيجة العائدة من فايسبوك في قاعدة البيانات لمدة 5 دقائق على سبيل المثال أو مدة أطول إذا كنت تفضل ذلك، وهذا سيكون له مردود جد إجابي على سرعة تحميل الموقع إذا كان يستقبل عدد كبير من الزيارات.
الكود في هذه الحالة سيكون كالتالي:
$fb_count = get_transient('facebook_count');
if ( false === $fb_count ) {
$return = wp_remote_get( 'http://graph.facebook.com/?id=http://www.mysite.com', array( 'timeout' => 10 ) );
$json = json_decode($return["body"], true);
$fb_count = isset($json["shares"]) ? intval($json["shares"]) : 0;
set_transient('facebook_count', $fb_count, 5 * MINUTE_IN_SECONDS);
}
باستعمال الخطوات المذكورة في هذه التدوينة يمكننا تحسين اداء القالب أو الإضافة التي نعمل عليها بشكل جد ملحوظ، نحن نتكلم عن تحسين الأداء بأجزاء من الثانية، لن يلاحظ إذا كانت الزيارات قليلة لكن إذا كانت الزيارات بالآلاف أجزاء الثانية تتضاعف أيضا بالآلاف …
شكرا لك على الوصول إلى نهاية التدوينة 🙂