Mysql
 sql >> Baza danych >  >> RDS >> Mysql

potrzebujesz pomocy w optymalizacji wordpress meta_query

Natknąłem się na ten problem i zdałem sobie sprawę, że problem dotyczy wszystkich INNER JOINS generowanych przez WordPress. Otrzymałem surowe zapytanie z WordPressa:

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

To nigdy się nie zakończyło i wiązało procesor przy bardzo dużym obciążeniu. Usunąłem ostatnie dwa INNER JOIN (i odpowiadające im klauzule WHERE) i otrzymałem wyniki w ciągu 2 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)
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 

Zdałem sobie więc sprawę, że usunięcie INNER JOINS było kluczem do przyspieszenia zapytania. Przepisałem zapytanie z tylko jednym wp_postmeta INNER JOIN i otrzymałem wyniki w ułamkach sekundy:

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

Dzięki temu rozwiązaniu stworzyłem filtr WordPress, aby przekonwertować zapytanie postmeta do szybszego formatu:

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

Ten filtr powinien znajdować się w pliku functions.php Twojego motywu WordPress.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak upewnić się, że w bazie danych MySQL nie ma wyścigu podczas inkrementacji pola?

  2. sprzężenie wewnętrzne i gdzie wydajność klauzuli in()?

  3. ckfinder php 2.6.2 widok ustawień, wyświetlanie, sortowanie nie działa

  4. Jak tworzyć i używać widoków MySQL

  5. Składnia SQL SELECT – wymieniona przez DBMS