Вопрос или проблема
У меня есть поисковая форма
с аргументом wp_query
. В этой форме много checkbox
.
Проблема начинается здесь: загрузка занимает много времени, когда вы выбираете все
варианты, этот запрос занимает почти минуту для выполнения. У кого-то была такая проблема раньше?
Я использовал эти коды в HTML
<form action="<?php echo site_url() ?>/wp-admin/admin-ajax.php" method="POST" id="filter">
<label> <input type="checkbox" name="real_time_antivirus" /> Антивирус в реальном времени </label></br>
.
.
.
<label> <input type="checkbox" name="adware_prevention" /> предотвращение рекламы </label></br>
<button>Применить фильтр</button>
<input type="hidden" name="action" value="myfilter">
в functions.php
add_action('wp_ajax_myfilter', 'misha_filter_function'); // wp_ajax_{ДЕЙСТВИЕ ЗДЕСЬ}
add_action('wp_ajax_nopriv_myfilter', 'misha_filter_function');
function misha_filter_function(){
$args = array(
'posts_per_page' =>-1,
);
$args['meta_query'] = array( 'relation'=>'AND' );
// Antivirus_featured_scaning
if( isset( $_POST['real_time_antivirus'] ) && $_POST['real_time_antivirus'] == 'on' )
$args['meta_query'][] = array(
'key' => 'antivirus_antivirus_featured_scaning',
'value' => 'real_time_antivirus',
'compare' => 'LIKE'
);
if( isset( $_POST['manual_virus_scanning'] ) && $_POST['manual_virus_scanning'] == 'on' )
$args['meta_query'][] = array(
'key' => 'antivirus_antivirus_featured_scaning',
'value' => 'manual_virus_scanning',
'compare' => 'LIKE'
);
if( isset( $_POST['usb_virus_scan'] ) && $_POST['usb_virus_scan'] == 'on' )
$args['meta_query'][] = array(
'key' => 'antivirus_antivirus_featured_scaning',
'value' => 'usb_virus_scan',
'compare' => 'LIKE'
);
if( isset( $_POST['registry_startup_scan'] ) && $_POST['registry_startup_scan'] == 'on' )
$args['meta_query'][] = array(
'key' => 'antivirus_antivirus_featured_scaning',
'value' => 'registry_startup_scan',
'compare' => 'LIKE'
);
if( isset( $_POST['auto_virus_scanning'] ) && $_POST['auto_virus_scanning'] == 'on' )
$args['meta_query'][] = array(
'key' => 'antivirus_antivirus_featured_scaning',
'value' => 'auto_virus_scanning',
'compare' => 'LIKE'
);
if( isset( $_POST['scheduled_scan'] ) && $_POST['scheduled_scan'] == 'on' )
$args['meta_query'][] = array(
'key' => 'antivirus_antivirus_featured_scaning',
'value' => 'scheduled_scan',
'compare' => 'LIKE'
);
// antivirus_featured_threat
if( isset( $_POST['anti_spyware'] ) && $_POST['anti_spyware'] == 'on' )
$args['meta_query'][] = array(
'key' => 'antivirus_antivirus_featured_threat',
'value' => 'anti_spyware',
'compare' => 'LIKE'
);
if( isset( $_POST['anti_worm'] ) && $_POST['anti_worm'] == 'on' )
$args['meta_query'][] = array(
'key' => 'antivirus_antivirus_featured_threat',
'value' => 'anti_worm',
'compare' => 'LIKE'
);
if( isset( $_POST['anti_trojan'] ) && $_POST['anti_trojan'] == 'on' )
$args['meta_query'][] = array(
'key' => 'antivirus_antivirus_featured_threat',
'value' => 'anti_trojan',
'compare' => 'LIKE'
);
if( isset( $_POST['anti_rootkit'] ) && $_POST['anti_rootkit'] == 'on' )
$args['meta_query'][] = array(
'key' => 'antivirus_antivirus_featured_threat',
'value' => 'anti_rootkit',
'compare' => 'LIKE'
);
if( isset( $_POST['anti_phishing'] ) && $_POST['anti_phishing'] == 'on' )
$args['meta_query'][] = array(
'key' => 'antivirus_antivirus_featured_threat',
'value' => 'anti_phishing',
'compare' => 'LIKE'
);
if( isset( $_POST['anti_spam'] ) && $_POST['anti_spam'] == 'on' )
$args['meta_query'][] = array(
'key' => 'antivirus_antivirus_featured_threat',
'value' => 'anti_spam',
'compare' => 'LIKE'
);
if( isset( $_POST['email_protection'] ) && $_POST['email_protection'] == 'on' )
$args['meta_query'][] = array(
'key' => 'antivirus_antivirus_featured_threat',
'value' => 'email_protection',
'compare' => 'LIKE'
);
if( isset( $_POST['chat_im_protection'] ) && $_POST['chat_im_protection'] == 'on' )
$args['meta_query'][] = array(
'key' => 'antivirus_antivirus_featured_threat',
'value' => 'chat_im_protection',
'compare' => 'LIKE'
);
if( isset( $_POST['adware_prevention'] ) && $_POST['adware_prevention'] == 'on' )
$args['meta_query'][] = array(
'key' => 'antivirus_antivirus_featured_threat',
'value' => 'adware_prevention',
'compare' => 'LIKE'
);
$query = new WP_Query( $args );
Спасибо за любую помощь.
Да, я могу представить, что этот запрос будет довольно сложным.
Основная причина в том, что каждое дополнительное условие для значения метаданных поста может вызывать дополнительный SQL JOIN между таблицей wp_posts и таблицей wp_posts, и JOIN’ы могут быть экспоненциально дорогими. Я удивлён, что он вообще возвращается за минуту, если вы выбираете все эти варианты. Эта проблема будет усугубляться по мере увеличения размера вашей таблицы wp_postmeta.
При этом неясно, почему вы используете LIKE
здесь вместо =
для значения сравнения, если вам не нужно действительно сопоставлять строки, которые содержат параметр value
? Это может существенно повлиять на скорость, так как LIKE
более затратен, чем =
в SQL.
Кроме того, из-за того, как этот запрос работает внутренне в WP_Query, вам может быть трудно заставить его работать быстрее. Возможно, вы находитесь на том этапе, когда вам нужна другая структура данных или нужно сделать что-то более индивидуальное, не используя WP_Query и структуру ключ-значение таблицы wp_postmeta. Или вы могли бы рассмотреть возможность ограничения количества этих опций, которые пользователи могут выбирать.
Надеюсь, это поможет
Запрос очень медленный, потому что он ищет посты по их значениям метаданных. Использование meta_query
по своей сути медленно, и это очень тяжело и дорого для сервера базы данных. Оно становится еще более медленным по мере увеличения количества постов в базе данных. Вот почему эти запросы выполняются быстро, когда сайт маленький, но со временем становятся медленнее.
Если вы хотите хранить данные для фильтрации или поиска постов, используйте вместо этого пользовательскую таксономию.
- Метаданные поста оптимизированы для поиска значений, когда вы уже знаете ID поста.
- Таксономии оптимизированы для поиска постов, когда вы уже знаете значения.
Если вы используете ACF или Field Manager, эти плагины могут быть настроены на использование таксономий для этих полей.
Ответ или решение
Проблема с производительностью WP_Query и решение
Использование WP_Query с множественными аргументами meta_query может значительно замедлить загрузку страницы, особенно когда количество записей в базе данных велико. В вашем случае, где форма поиска включает множество чекбоксов, это может привести к критически долгому времени выполнения запросов. Давайте подробно рассмотрим причины этой проблемы и предложим возможные решения.
Причины медленной загрузки
-
Сложные SQL-запросы:
Каждый дополнительный элемент в массиве meta_query приводит к сложному SQL-запросу, обременяющему систему большим количеством JOIN-операций, так как WordPress выполняет каждую проверкуmeta_query
как отдельную выборку из таблицы postmeta. Это может создавать избыточные нагрузки при увеличении объема данных в таблице. -
Использование оператора LIKE:
Оператор LIKE требует больше ресурсов по сравнению с равенством (=), поскольку он исследует строки на наличие совпадений, что замедляет обработку. Если можно использовать оператор равенства, предпочтительнее будет именно его. -
Объем данных:
Чем больше записей содержится в таблице wp_postmeta, тем дольше будет выполняться запрос. Если у вас много метаданных, ресурсозатраты будут возрастать экспоненциально.
Рекомендации по улучшению производительности
-
Оптимизация использования meta_query:
- Попробуйте исключать те поля, которые не являются критически важными для фильтрации, или минимизируйте их количество.
- Используйте оператор
=
в тех случаях, когда это возможно, вместоLIKE
, который требует больше вычислений.
-
Перепроектирование структуры данных:
- Рассмотрите возможность использования пользовательских таксономий вместо метаданных для фильтрации. Таксономии оптимизируют запросы, когда вы ищете по значениям, а метаданные — когда знаете идентификатор поста. Это может существенно улучшить производительность.
- Если доступны передовые плагины, такие как ACF (Advanced Custom Fields), вы также можете использовать таксономии для полей с метаданными.
-
Лимитирование выбора опций:
- Подумайте о возможности ограничить количество чекбоксов, которые могут выбирать пользователи. Можно внедрить функционал, при котором выбор нескольких опций одновременно будет невозможен.
-
Кэширование:
- Используйте кэширование запросов, чтобы ускорить их выполнение. В WordPress доступны разные плагины для кэширования, которые могут значительно снизить нагрузку на базу данных.
-
Анализ и индексация базы данных:
- Проверьте индексацию таблицы wp_postmeta. Убедитесь, что у вас создан специальный индекс по столбцу
meta_key
, это может сократить время выборки. - Используйте анализ производительности для выявления узких мест в вашем запросе.
- Проверьте индексацию таблицы wp_postmeta. Убедитесь, что у вас создан специальный индекс по столбцу
Заключение
Проблемы с производительностью при использовании WP_Query с множественными аргументами meta_query — распространенная ситуация. Однако, обеспечив правильную оптимизацию запросов, изменение структуры данных и использование таксономий, вы можете значительно улучшить время отклика вашего веб-сайта. Важно помнить, что с ростом объема данных время выполнения запросов будет неизбежно увеличиваться, и системный подход к проектированию и оптимизации значительно упростит вам жизнь. Если у вас возникают дополнительные вопросы, не стесняйтесь обращаться за помощью!