Intereting Posts
Настройка внешнего интерфейса на основе postmeta, не загружающего перевод Пользовательская почтовая страница с одной страницей возвращает ошибку 404 WordPress переписывает мой URL-адрес, когда я использую разбиение на страницы Как oEmbed из настраиваемого поля, реагируя на размер контейнера и отзывчивый Как создать редактор кода для моего плагина.? Исключение страниц, не работающих Фильтрация результатов поиска Отображение сообщений исключительно в их категории (не родительских) Не уверен, что я должен создать несколько настраиваемых типов сообщений Создавайте сообщения WordPress из массива JSON, используя плагин в admin Изменить размер миниатюры сообщения создает ужасное качество изображения. Любая помощь? Проблема глубины с использованием wp_list_pages для субнавигации Редактирование ссылок в нижнем колонтитуле WordPress Темы с зашифрованным кодом Base64? Улучшение или оптимизация очень медленного запроса Форма представления на лицевой стороне не прикрепляет пользовательский тип сообщения

Оптимизировать запрос MySQL с несколькими таксономиями?

( Примечание модератора: Название было первоначально: «оптимизация запросов / баз данных»)

Я написал функцию для пользовательской панели поиска «фильтр», которая позволяет пользователям выбирать термины из четырех пользовательских таксономий. Я запускаю запросы непосредственно к базе данных, и запрос составляет в среднем полсекунды для выполнения (с условиями для всех четырех таксономий и одного результата).

Мне это кажется довольно медленным. Мне было интересно, есть ли что-нибудь, что я могу сделать, чтобы оптимизировать запрос или даже базу данных, чтобы сделать это более эффективным / быстрым. Возможно, даже написать мнение? У меня есть опыт работы с MS-SQL, но не много с MySQL, и я не уверен, как все по-другому.

Вот мой код функции:

function filter_resources($phase,$wa,$aus,$topics){ global $wpdb; $querystr=" SELECT * FROM $wpdb->posts A LEFT JOIN $wpdb->term_relationships B ON(A.ID = B.object_id) LEFT JOIN $wpdb->term_taxonomy C ON(B.term_taxonomy_id = C.term_taxonomy_id) LEFT JOIN $wpdb->terms D ON(C.term_id = D.term_id) LEFT JOIN $wpdb->term_relationships BB ON(A.ID = BB.object_id) LEFT JOIN $wpdb->term_taxonomy CC ON(BB.term_taxonomy_id = CC.term_taxonomy_id) LEFT JOIN $wpdb->terms DD ON(CC.term_id = DD.term_id) LEFT JOIN $wpdb->term_relationships BBB ON(A.ID = BBB.object_id) LEFT JOIN $wpdb->term_taxonomy CCC ON(BBB.term_taxonomy_id = CCC.term_taxonomy_id) LEFT JOIN $wpdb->terms DDD ON(CCC.term_id = DDD.term_id) LEFT JOIN $wpdb->term_relationships BBBB ON(A.ID = BBBB.object_id) LEFT JOIN $wpdb->term_taxonomy CCCC ON(BBBB.term_taxonomy_id = CCCC.term_taxonomy_id) LEFT JOIN $wpdb->terms DDDD ON(CCCC.term_id = DDDD.term_id) WHERE A.post_type = 'resources' AND A.post_status = 'publish' AND C.taxonomy = 'phase-of-learning' AND D.term_id = '$phase' AND CC.taxonomy = 'wa-curriculum' AND DD.term_id = '$wa' AND CCC.taxonomy = 'australian-curriculum' AND DDD.term_id = '$aus' AND CCCC.taxonomy = 'topics' AND DDDD.term_id = '$topics' ORDER BY A.post_date DESC"; return $wpdb->get_results($querystr,OBJECT); } 

Благодаря!

Solutions Collecting From Web of "Оптимизировать запрос MySQL с несколькими таксономиями?"

Хотя это действительно вопрос MySQL, он помогает понять схему WordPress SQL, а также мне нравится пытаться оптимизировать SQL-запросы, а не отправлять вас в StackOverflow. Я постараюсь вам ответить. Вы все еще можете опубликовать его там, чтобы получить другие мнения.

И хотя я не полностью понимаю ваше требование, я думаю, что понимаю, что вы просите, я думаю, что я делаю это, я хотел бы представить следующее, чтобы узнать, удовлетворяет ли оно вашим потребностям. У меня нет ваших данных, поэтому мне очень сложно, что это действительно работает, но, как я уже сказал, я думаю, что это отвечает вашим потребностям:

 function filter_resources($phase,$wa,$aus,$topics){ global $wpdb; $sql =<<<SQL SELECT t.slug,p.* FROM wp_posts p INNER JOIN wp_term_relationships tr ON p.ID=tr.object_id INNER JOIN wp_term_taxonomy tt ON tr.term_taxonomy_id = tt.term_taxonomy_id INNER JOIN wp_terms t ON tt.term_id = t.term_id WHERE 1=1 AND p.post_type = 'resources' AND p.post_status = 'publish' AND t.term_id IN (%d,%d,%d,%d) AND CONCAT(tt.taxonomy,'/',t.term_id) IN ( 'phase-of-learning/%s', 'wa-curriculum/%s', 'australian-curriculum/%s', 'topics/%s' ) GROUP BY p.ID HAVING COUNT(*)=4 ORDER BY p.post_date DESC SQL; $sql = $wpdb->prepare($sql, $phase,$wa,$aus,$topics, // For the %d replacements $phase,$wa,$aus,$topics // For the %s replacements ); $results = $wpdb->get_results($sql,OBJECT); return $results; } 

В основном это дает вам все должности, на которых применяются все ваши таксономические условия, и делает это, делая запрос произвольной формы, чтобы соответствовать всем сообщениям, которые применяют таксономию / условия, но ограничивает только те должности, которые используют все термины, применяемые группировкой по wp_post.ID и найти все записи, для которых сообщение добавлено 4 раза. Когда вы запускаете MySQL EXPLAIN оптимизация выглядит неплохо по сравнению с тем, что у вас было; к ним присоединилось еще несколько таблиц. Надеюсь, это была логика, в которой вы нуждались.

Кэширование с помощью API переходных процессов

И если вы пытаетесь повысить производительность, вы также можете подумать о том, чтобы кешировать результаты в «переходные» в течение ограниченного времени (1 час, 4 часа, 12 часов или более?). В этом блоге описано, как использовать API-интерфейс WordPress Transients :

  • Обзор API переходных процессов WordPress

Вот основная логика переходных процессов:

 define('NUM_HOURS',4); // Time to cache set for your use case $data = get_transient( 'your_transient_key' ); if( !$data ) { $data = // Do something to get your data here set_transient( 'your_transient_key', $data, 60 * 60 * NUM_HOURS ); } 

Чтобы использовать переходные процессы в вашей функции filter_resources() он может выглядеть следующим образом:

 define('RESOURCE_CACHE_HOURS',4); function filter_resources($phase,$wa,$aus,$topics){ $resources = get_transient( 'yoursite_filtered_resources' ); if(!$resources) { global $wpdb; $sql =<<<SQL SELECT t.slug,p.* FROM wp_posts p INNER JOIN wp_term_relationships tr ON p.ID=tr.object_id INNER JOIN wp_term_taxonomy tt ON tr.term_taxonomy_id = tt.term_taxonomy_id INNER JOIN wp_terms t ON tt.term_id = t.term_id WHERE 1=1 AND p.post_type = 'resources' AND p.post_status = 'publish' AND t.term_id IN (%d,%d,%d,%d) AND CONCAT(tt.taxonomy,'/',t.term_id) IN ( 'phase-of-learning/%s', 'wa-curriculum/%s', 'australian-curriculum/%s', 'topics/%s' ) GROUP BY p.ID HAVING COUNT(*)=4 ORDER BY p.post_date DESC SQL; $sql = $wpdb->prepare($sql, $phase,$wa,$aus,$topics, // For the %d replacements $phase,$wa,$aus,$topics // For the %s replacements ); $resources = $wpdb->get_results($sql,OBJECT); $hours = RESOURCE_CACHE_HOURS * 60 * 60;  set_transient( 'yoursite_filtered_resources', $resources, $hours); } return $resources; } 

ОБНОВИТЬ

Вот еще один пример кода, который пытается обрабатывать случаи, когда пользователь выбирает менее четырех критериев:

 define('RESOURCE_CACHE_HOURS',4); function filter_resources($phase,$wa,$aus,$topics){ $resources = get_transient( 'yoursite_filtered_resources' ); if(!$resources) { $terms = $taxterms = array(); if (!empty($phase)) $taxterms[$phase] = 'phase-of-learning/%s'; if (!empty($wa)) $taxterms[$wa] = 'wa-curriculum/%s'; if (!empty($aus)) $taxterms[$aus] = 'axustralian-curriculum/%s'; if (!empty($topics)) $taxterms[$topics] = 'topics/%s'; $count = count($taxterms); $having = ($count==0 ? '' : "HAVING COUNT(*)={$count}"); $values = array_keys(array_flip($tax_terms)); $values = array_merge($values,$values); // For %d and $s $taxterms = implode("','",$taxterms); $terms = implode(',',array_fill(0,$count,'d%')); global $wpdb; $sql =<<<SQL SELECT t.slug,p.* FROM wp_posts p INNER JOIN wp_term_relationships tr ON p.ID=tr.object_id INNER JOIN wp_term_taxonomy tt ON tr.term_taxonomy_id = tt.term_taxonomy_id INNER JOIN wp_terms t ON tt.term_id = t.term_id WHERE 1=1 AND p.post_type = 'resources' AND p.post_status = 'publish' AND t.term_id IN ({$terms}) AND CONCAT(tt.taxonomy,'/',t.term_id) IN ('{$taxterms}') GROUP BY p.ID {$having} ORDER BY p.post_date DESC SQL; $sql = $wpdb->prepare($sql,$values); $resources = $wpdb->get_results($sql,OBJECT); $hours = RESOURCE_CACHE_HOURS * 60 * 60; set_transient( 'yoursite_filtered_resources', $resources, $hours); } return $resources; } , define('RESOURCE_CACHE_HOURS',4); function filter_resources($phase,$wa,$aus,$topics){ $resources = get_transient( 'yoursite_filtered_resources' ); if(!$resources) { $terms = $taxterms = array(); if (!empty($phase)) $taxterms[$phase] = 'phase-of-learning/%s'; if (!empty($wa)) $taxterms[$wa] = 'wa-curriculum/%s'; if (!empty($aus)) $taxterms[$aus] = 'axustralian-curriculum/%s'; if (!empty($topics)) $taxterms[$topics] = 'topics/%s'; $count = count($taxterms); $having = ($count==0 ? '' : "HAVING COUNT(*)={$count}"); $values = array_keys(array_flip($tax_terms)); $values = array_merge($values,$values); // For %d and $s $taxterms = implode("','",$taxterms); $terms = implode(',',array_fill(0,$count,'d%')); global $wpdb; $sql =<<<SQL SELECT t.slug,p.* FROM wp_posts p INNER JOIN wp_term_relationships tr ON p.ID=tr.object_id INNER JOIN wp_term_taxonomy tt ON tr.term_taxonomy_id = tt.term_taxonomy_id INNER JOIN wp_terms t ON tt.term_id = t.term_id WHERE 1=1 AND p.post_type = 'resources' AND p.post_status = 'publish' AND t.term_id IN ({$terms}) AND CONCAT(tt.taxonomy,'/',t.term_id) IN ('{$taxterms}') GROUP BY p.ID {$having} ORDER BY p.post_date DESC SQL; $sql = $wpdb->prepare($sql,$values); $resources = $wpdb->get_results($sql,OBJECT); $hours = RESOURCE_CACHE_HOURS * 60 * 60; set_transient( 'yoursite_filtered_resources', $resources, $hours); } return $resources; } 

Если вам не нужно оставаться обратно совместимым с WP 3.0, вы можете просто воспользоваться расширенной поддержкой запросов таксономии в WP 3.1.

Код, который генерирует SQL, можно найти в wp-includes / taxonomy.php

Прежде всего, используйте внутренние соединения, а не левые соединения. Левые соединения будут вынуждать план запроса, который сканирует всю таблицу сообщений, пока не найдет подходящую запись через фильтры терминалов.

Во-вторых, вы можете уменьшить количество необходимых объединений, предварительно используя условия get_term ().

Объединив два, ваш запрос станет примерно таким:

 SELECT * FROM $wpdb->posts posts JOIN $wpdb->term_relationships termA ON posts.ID = termA.object_id AND termA.term_taxonomy_id = $termA_taxid JOIN $wpdb->term_relationships termB ON posts.ID = termB.object_id AND termB.term_taxonomy_id = $termB_taxid JOIN $wpdb->term_relationships termC ON posts.ID = termC.object_id AND termC.term_taxonomy_id = $termC_taxid JOIN $wpdb->term_relationships termD ON posts.ID = termD.object_id AND termD.term_taxonomy_id = $termD_taxid WHERE ... 

Который должен давать те же результаты с 5 связанными таблицами вместо 13 и с планом запроса, который начинается с поиска того, какие должности привязаны к тому, какой из членов имеет наименьшее значение в term_relationships.