sql >> Database teknologi >  >> RDS >> Mysql

har brug for hjælp til at optimere wordpress meta_query

Jeg stødte på dette problem og indså, at problemet var med alle INNER JOINS, der blev genereret af WordPress. Jeg fik den rå forespørgsel fra 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

Dette fuldførte aldrig og bandt CPU'en ved en meget høj belastning. Jeg fjernede de sidste to INNER JOINs (og tilsvarende WHERE-klausuler) og fik resultater på 2 sekunder:

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 

Så jeg indså, at fjernelse af INNER JOINS var nøglen til at fremskynde forespørgslen. Jeg omskrev forespørgslen med kun én wp_postmeta INNER JOIN og fik resultater på brøkdele af et sekund:

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

Med denne løsning oprettede jeg et WordPress-filter til at konvertere postmeta-forespørgslen til det hurtigere format:

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' );

Dette filter skal være placeret i functions.php-filen i dit WordPress-tema.



  1. SQL-udvælgelsesforespørgsel ved hjælp af joins, grupper efter og aggregerede funktioner

  2. Design af ikke-overlappende dato-tidsbegivenheder

  3. Oracle:Kombiner flere resultater i en underforespørgsel til en enkelt kommasepareret værdi

  4. Hvad er MariaDB Enterprise Cluster?