#php #mysql #sql #wordpress
#php #mysql #sql #wordpress
Вопрос:
У меня есть запрос MySQL для обработки довольно сложного поиска в WordPress, потому что я изо всех сил пытался заставить wp_query
делать все, что мне нужно.
Однако иногда выполнение запроса занимает много времени (иногда более 10 секунд!), А иногда, похоже, просто приводит к сбою сервера (media temple Grid), возвращая internal server error
или Error establishing database connection
.
Я не уверен, есть ли в запросе общая синтаксическая ошибка, которая вызывает его сбой, или нет, но по сути PHP, который генерирует запрос, выглядит следующим образом:
<?php
// declare wordpress database global
global $wpdb;
// order by option
$order = $_SESSION['search']['sort-by'];
// users lat, long and distance preferences
$lat = $_SESSION['search']['lat'];
$long = $_SESSION['search']['long'];
$radius = $_SESSION['search']['distance'];
// user search start/end date
$startDate = date('Ymd', strtotime($_SESSION['search']['from']));
$endDate = date('Ymd', strtotime($_SESSION['search']['to']));
// get the main category search ID
$maincat = get_term_by( 'slug', $_SESSION['search']['cat'], 'main-cat');
$maincat = $maincat->term_taxonomy_id;
// grab keywords, replace special chars and spaces
$keywords = $_SESSION['search']['keyword'];
$keywords = preg_replace('/[^A-Za-z0-9 ,]/u','', strip_tags($keywords));
$keywords = str_replace(' ', '', $keywords);
// put keywords into array
$subcatItems = explode(',', $keywords);
$keywords = $subcatItems;
// for each keywords get the sub category id's
$subcats = array();
$count = count($subcatItems) - 2;
for ($i = 0; $i <= $count; $i ) {
$subcatItems[$i] = get_term_by( 'slug', $subcatItems[$i], 'sub-cat');
if ($subcatItems[$i] != '') :
$subcatItems[$i] = $subcatItems[$i]->term_taxonomy_id;
array_push($subcats, $subcatItems[$i]);
endif;
}
if( $subcats != '' ) :
$subcats = implode(',', $subcats);
endif;
// select
$query = 'SELECT SQL_CALC_FOUND_ROWS wp_posts.*, ';
// geo locate
$query .= '( 3959 * acos(
cos( radians('.$lat.') )
* cos( radians( lat ) )
* cos( radians( lng ) - radians('.$long.') )
sin( radians('.$lat.') )
* sin( radians( lat ) )
) )
AS distance , lat AS latitude , lng AS longitude ';
// from
$query .= 'FROM wp_posts ';
// inner joins
$query .= 'INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id) ';
if ( $keywords != '' ) :
$query .= 'INNER JOIN wp_term_relationships AS tt1 ON (wp_posts.ID = tt1.object_id) ';
endif;
$query .= 'INNER JOIN wp_postmeta ON (wp_posts.ID = wp_postmeta.post_id) ';
$query .= 'INNER JOIN wp_postmeta AS mt1 ON (wp_posts.ID = mt1.post_id) ';
// if ordered by price, join post meta again
if( $order == 'mt2.meta_value 0' ) :
$query .= 'INNER JOIN wp_postmeta AS mt2 ON (wp_posts.ID = mt2.post_id) ';
endif;
// if there are keywords
if ( $keywords != '' ) :
$query .= 'INNER JOIN wp_postmeta AS mt3 ON (wp_posts.ID = mt3.post_id) ';
endif;
// join table to geo locate
$query .= 'INNER JOIN lat_lng_post ON wp_posts.ID = lat_lng_post.post_id ';
// basic filter
$query .= 'WHERE 1=1 ';
$query .= 'AND wp_posts.post_type = "event" ';
$query .= 'AND wp_posts.post_status = "publish" ';
// geo filter
$query .= 'AND lat_lng_post.lat = lat ';
$query .= 'AND lat_lng_post.lng = lng ';
// date filter
$query .= 'AND ( ';
$query .= '(wp_postmeta.meta_key LIKE "date_%_start-date" AND CAST(wp_postmeta.meta_value AS SIGNED) <= "'.$endDate.'") ';
$query .= 'AND (mt1.meta_key LIKE "date_%_end-date" AND CAST(mt1.meta_value AS SIGNED) >= "'.$startDate.'") ';
$query .= 'AND substr(wp_postmeta.meta_key, 1, 6) = substr(mt1.meta_key, 1, 6) ';
$query .= ') ';
// taxonomies filter
$query .= 'AND ( wp_term_relationships.term_taxonomy_id IN ('.$maincat.') ) ';
// if keywords
if ( $_SESSION['search']['keyword'] != '' ) :
$query .= 'AND ( ';
// for each keyword, and a statement to check post title
$keywordCount = 0;
foreach ( $keywords as $keyword ) :
if( $keyword != '' ) :
if( $keywordCount == 0 ) :
$query .= '(wp_posts.post_title LIKE "%'.$keyword.'%") ';
else :
$query .= 'OR (wp_posts.post_title LIKE "%'.$keyword.'%") ';
endif;
endif;
$keywordCount ;
endforeach;
// for each keyword, and a statement to check description
foreach ( $keywords as $keyword ) :
if( $keyword != '' ) :
$query .= 'OR (mt3.meta_key = "description" AND mt3.meta_value LIKE "%'.$keyword.'%") ';
endif;
endforeach;
// for each keyword, and a statement to check sub category taxonomy
if( $subcats != '' ) :
$query .= 'OR ( tt1.term_taxonomy_id IN ('.$subcats.') )';
endif;
$query .= ') ';
endif;
// if ordered by adult
if( $order == 'mt2.meta_value 0' ) :
$query .= 'AND mt2.meta_key = "adult" ';
endif;
// grouping and sorting
$query .= 'GROUP BY wp_posts.ID ';
$query .= 'HAVING distance <= '.$radius.' ';
$query .= 'ORDER BY '.$order.' ASC ';
$query .= 'LIMIT 0, 10';
$events = $wpdb->get_results( $query, 'OBJECT' );
?>
Если у кого-нибудь есть какие-либо идеи, пожалуйста, дайте мне знать! И если вам нужна дополнительная информация, я рад ее предоставить 🙂
Редактировать
Запрос, похоже, испытывает гораздо большие трудности, когда в поиске есть ключевые слова. Я не уверен, есть ли лучший способ написания логики вокруг :
if ( $_SESSION['search']['keyword'] != '' ) :
$query .= 'AND ( ';
// for each keyword, and a statement to check post title
$keywordCount = 0;
foreach ( $keywords as $keyword ) :
if( $keyword != '' ) :
if( $keywordCount == 0 ) :
$query .= '(wp_posts.post_title LIKE "%'.$keyword.'%") ';
else :
$query .= 'OR (wp_posts.post_title LIKE "%'.$keyword.'%") ';
endif;
endif;
$keywordCount ;
endforeach;
// for each keyword, and a statement to check description
foreach ( $keywords as $keyword ) :
if( $keyword != '' ) :
$query .= 'OR (mt3.meta_key = "description" AND mt3.meta_value LIKE "%'.$keyword.'%") ';
endif;
endforeach;
// for each keyword, and a statement to check sub category taxonomy
if( $subcats != '' ) :
$query .= 'OR ( tt1.term_taxonomy_id IN ('.$subcats.') )';
endif;
$query .= ') ';
endif;
РЕДАКТИРОВАТЬ 2
Еще одна мысль, которая у меня только что возникла, возможно, было бы быстрее разделить запрос на отдельные запросы? Итак, сначала просто завершите запрос geo, возьмите эти идентификаторы post и выполните запрос даты, а затем, возможно, выполните запрос ключевых слов? Я совсем новичок в MySQL, поэтому не слишком уверен, как это оптимизировать :/
Комментарии:
1. ну, это действительно тяжелый запрос. Возможно, перемещение вычисления расстояния из mysql помогло бы.
2. Возможно ли перенести это из MySQL? Все широты и долготы, с которыми он должен сверяться, хранятся в базе данных :/
3. Вы просматривали журнал медленных запросов сервера mysql? Чтобы исключить общую синтаксическую ошибку SQL, вы могли бы добавить сгенерированный запрос в файл журнала непосредственно перед вызовом
$events = $wpdb->get_results( $query, 'OBJECT' );
. С помощью этого журнала вы могли бы попытаться с помощьюEXPLAIN
оптимизировать запрос.4. На самом деле я не смотрел на это, я пытался добавить EXPLAIN к запросу раньше, но он никогда не запускается, я не уверен, связано ли это как-то с $ wpdb? Это выдает синтаксические ошибки для MySQL, поэтому я бы предположил, что они там появятся, если честно?
Ответ №1:
Попробуйте добавить окончательные условия к объединениям (несколько условий объединения).
Если вы используете несколько условий при объединении вместо того, чтобы получать огромный набор, а затем помещать условие в конце, ваш набор будет меньше, а время отклика может быть больше.
например, у вас есть окончательное условие:
AND wp_posts.post_type = "event"
Вы могли бы поместить его в первое объединение
INNER JOIN wp_term_relationships ON (wp_posts.ID = wp_term_relationships.object_id) AND wp_posts.post_type = "event"
INNER JOIN...
и так далее.
Комментарии:
1. Привет, только что попробовал это, казалось, это помогло после начальной загрузки сайта, я предполагаю, что часть этого кэшируется, но эта первая загрузка все еще довольно большая, и я все еще получаю 500 ошибок :/
2. Вы также указали «..и расстояние <= $ radius» при первом объединении?
3. Можете ли вы проверить, действительно ли время отклика улучшилось? (например, ввод команды в phpmyadmin или аналогичный)
4. Я посмотрю, есть ли разница во времени выполнения 🙂
5. Просто попробовал перемещать условия одно за другим, и, похоже, это увеличивает время выполнения примерно на 1 секунду для каждой вещи, которую я перемещаю :/