Ik kwam dit probleem tegen en realiseerde me dat het probleem lag bij alle INNER JOINS die door WordPress werden gegenereerd. Ik kreeg de onbewerkte vraag van WordPress:
SELECT wp_posts.* FROM wp_posts
INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)
INNER JOIN wp_postmeta AS mt1 ON (wp_posts.ID = mt1.post_id)
INNER JOIN wp_postmeta AS mt2 ON (wp_posts.ID = mt2.post_id)
INNER JOIN wp_postmeta AS mt3 ON (wp_posts.ID = mt3.post_id)
INNER JOIN wp_postmeta AS mt4 ON (wp_posts.ID = mt4.post_id)
INNER JOIN wp_postmeta AS mt5 ON (wp_posts.ID = mt5.post_id) WHERE 1=1 AND ( wp_term_relationships.term_taxonomy_id IN (7,11,12,13,14,15) AND wp_posts.ID NOT IN (
SELECT object_id
FROM wp_term_relationships
WHERE term_taxonomy_id IN (10)
) ) AND wp_posts.post_type IN ('post', 'page', 'attachment', 'product', 'store_page') AND (wp_posts.post_status = 'publish') AND ( (wp_postmeta.meta_key = 'product_type' AND CAST(wp_postmeta.meta_value AS CHAR) = 'type_pre_ground')
OR (mt1.meta_key = 'product_type2' AND CAST(mt1.meta_value AS CHAR) = 'type_pre_ground')
OR (mt2.meta_key = 'product_type3' AND CAST(mt2.meta_value AS CHAR) = 'type_pre_ground')
OR (mt3.meta_key = 'product_type4' AND CAST(mt3.meta_value AS CHAR) = 'type_pre_ground')
OR (mt4.meta_key = 'product_type5' AND CAST(mt4.meta_value AS CHAR) = 'type_pre_ground')
OR (mt5.meta_key = 'product_type6' AND CAST(mt5.meta_value AS CHAR) = 'type_pre_ground') ) GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC
Dit is nooit voltooid en legde de CPU vast met een zeer hoge belasting. Ik heb de laatste twee INNER JOIN's (en bijbehorende WHERE-clausules) verwijderd en kreeg binnen 2 seconden resultaten:
SELECT wp_posts.* FROM wp_posts
INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id)
INNER JOIN wp_postmeta AS mt1 ON (wp_posts.ID = mt1.post_id)
INNER JOIN wp_postmeta AS mt2 ON (wp_posts.ID = mt2.post_id)
INNER JOIN wp_postmeta AS mt3 ON (wp_posts.ID = mt3.post_id) WHERE 1=1 AND ( wp_term_relationships.term_taxonomy_id IN (7,11,12,13,14,15) AND wp_posts.ID NOT IN (
SELECT object_id
FROM wp_term_relationships
WHERE term_taxonomy_id IN (10)
) ) AND wp_posts.post_type IN ('post', 'page', 'attachment', 'product', 'store_page') AND (wp_posts.post_status = 'publish') AND ( (wp_postmeta.meta_key = 'product_type' AND CAST(wp_postmeta.meta_value AS CHAR) = 'type_pre_ground')
OR (mt1.meta_key = 'product_type2' AND CAST(mt1.meta_value AS CHAR) = 'type_pre_ground')
OR (mt2.meta_key = 'product_type3' AND CAST(mt2.meta_value AS CHAR) = 'type_pre_ground')
OR (mt3.meta_key = 'product_type4' AND CAST(mt3.meta_value AS CHAR) = 'type_pre_ground') ) GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC
Dus ik realiseerde me dat het verwijderen van de INNER JOINS de sleutel was om de query te versnellen. Ik herschreef de vraag met slechts één wp_postmeta INNER JOIN en kreeg resultaten in fracties van een seconde:
SELECT wp_posts.* FROM wp_posts
INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id)
INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id) WHERE 1=1 AND ( wp_term_relationships.term_taxonomy_id IN (7,11,12,13,14,15) AND wp_posts.ID NOT IN (
SELECT object_id
FROM wp_term_relationships
WHERE term_taxonomy_id IN (10)
) )
AND wp_posts.post_type IN ('post', 'page', 'attachment', 'product', 'store_page')
AND (wp_posts.post_status = 'publish')
AND ( (wp_postmeta.meta_key = 'product_type' AND CAST(wp_postmeta.meta_value AS CHAR) = 'type_pre_ground')
OR (wp_postmeta.meta_key = 'product_type2' AND CAST(wp_postmeta.meta_value AS CHAR) = 'type_pre_ground')
OR (wp_postmeta.meta_key = 'product_type3' AND CAST(wp_postmeta.meta_value AS CHAR) = 'type_pre_ground')
OR (wp_postmeta.meta_key = 'product_type4' AND CAST(wp_postmeta.meta_value AS CHAR) = 'type_pre_ground')
OR (wp_postmeta.meta_key = 'product_type5' AND CAST(wp_postmeta.meta_value AS CHAR) = 'type_pre_ground')
OR (wp_postmeta.meta_key = 'product_type6' AND CAST(wp_postmeta.meta_value AS CHAR) = 'type_pre_ground') )
GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC
Met deze oplossing heb ik een WordPress-filter gemaakt om de postmeta-query naar het snellere formaat te converteren:
function custom_get_meta_sql( $meta_sql )
{
global $wpdb;
$posts_table = $wpdb->prefix . 'posts';
$postmeta_table = $wpdb->prefix . 'postmeta';
//use single INNER JOIN
$meta_sql['join'] = " INNER JOIN {$postmeta_table} AS pmta ON ({$posts_table}.ID = pmta.post_id) ";
//replace the mtNN aliases with wp_postmeta
$where_clause = $meta_sql['where'];
$where_clause = str_replace("{$postmeta_table}.", 'pmta.', $where_clause);
$where_clause = preg_replace('/mt\d+\.meta_/i', 'pmta.meta_', $where_clause);
$meta_sql['where'] = $where_clause;
return $meta_sql;
}
add_filter( 'get_meta_sql', 'custom_get_meta_sql' );
Dit filter zou zich in het bestand Functions.php van uw WordPress-thema moeten bevinden.