2016-11-28 3 views
0

Я довольно новичок в MySQL и работал над следующим запросом, чтобы вывести список значений из таблиц wordpress users/usermeta. Запрос работает отдельно от производительности, это ужасно, и я не уверен, как его улучшить.Оптимизация/запрос MySQL

Задание длится 12+ секунд, и только с 400 пользователями это станет огромной проблемой, если будет добавлено больше.

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

Это запрос по умолчанию, полный запрос добавляет дополнительные вычисления с использованием значений lat/long для определения расстояния для поиска в почтовом индексе, однако это, похоже, не добавляет много дополнительного времени.

Основная часть, с которой я боролся, заключается в том, что значения сохраняются как meta_key и meta_value с ассоциированным user_id как внешним ключом.

SELECT DISTINCT 
    wp_users.ID, 
    wp_users.user_email, 
    city_latitude.meta_value as cityLat, 
    city_longitude.meta_value as cityLong, 
    service_name.meta_value as service_name, 
    service_address.meta_value as service_address, 
    service_category.meta_value as service_category, 
    service_level.meta_value as service_level, 
    service_info.meta_value as service_info, 
    service_area.meta_value as service_area, 
    service_active.meta_value as service_active, 
    service_keyword.meta_value as service_keyword 
FROM 
    wp_usermeta AS city_latitude 
    LEFT JOIN wp_usermeta as city_longitude ON city_latitude.user_id = city_longitude.user_id 
    LEFT JOIN wp_usermeta as service_name ON service_name.user_id = city_longitude.user_id 
    LEFT JOIN wp_usermeta as service_category ON service_category.user_id = city_longitude.user_id 
    LEFT JOIN wp_usermeta as service_address ON service_address.user_id = city_longitude.user_id 
    LEFT JOIN wp_usermeta as service_level ON service_level.user_id = city_longitude.user_id 
    LEFT JOIN wp_usermeta as service_info ON service_info.user_id = city_longitude.user_id 
    LEFT JOIN wp_usermeta as service_area ON service_area.user_id = city_longitude.user_id 
    LEFT JOIN wp_usermeta as service_active ON service_active.user_id = city_longitude.user_id 
    LEFT JOIN wp_usermeta as service_keyword ON service_keyword.user_id = city_longitude.user_id 
    INNER JOIN wp_users ON wp_users.ID = city_latitude.user_id 

WHERE city_latitude.meta_key = 'service_lat' 
    AND city_longitude.meta_key = 'service_long' 
    AND (service_name.meta_key = 'service_name' AND service_name.meta_value != 'Anonymous') 
    AND (service_category.meta_key = 'service_category' ".$query_category.") 
    AND service_address.meta_key = 'service_address' 
    AND (service_level.meta_key = 'wp_user_level' AND service_level.meta_value = 0) 
    AND service_info.meta_key = 'service_additional' 
    AND service_area.meta_key = 'service_area' 
    AND service_keyword.meta_key = 'service_keywords' 
    AND (service_active.meta_key = 'active' AND service_active.meta_value = 1) 
ORDER BY service_name ASC 

Я обновил запрос с некоторыми из приведенных ниже предложений, которые уже имеют большое значение. Я все еще думаю, что сам запрос можно улучшить, уменьшив количество объединений и т. Д., Если у кого-то есть больше идей, которые я бы хотел их услышать.

Это запрос, который включает изменения и дополнительную часть для поиска по расстоянию.

SELECT DISTINCT 
    wp_users.ID, 
    wp_users.user_email, 
    city_latitude.meta_value as cityLat, 
    city_longitude.meta_value as cityLong, 
    service_name.meta_value as service_name, 
    service_address.meta_value as service_address, 
    service_category.meta_value as service_category, 
    service_level.meta_value as service_level, 
    service_info.meta_value as service_info, 
    service_area.meta_value as service_area, 
    service_active.meta_value as service_active, 
    service_keyword.meta_value as service_keyword, 
    ((ACOS(SIN($userLat * PI()/180) * SIN(city_latitude.meta_value * PI()/180) + COS($userLat * PI()/180) * COS(city_latitude.meta_value * PI()/180) * COS(($userLng - city_longitude.meta_value) * PI()/180)) * 180/PI()) * 60 * 1.1515) AS distance 
FROM 
    wp_usermeta AS usermeta 
    LEFT JOIN wp_usermeta as city_longitude ON city_longitude.user_id = usermeta.user_id AND city_longitude.meta_key = 'service_long' 
    LEFT JOIN wp_usermeta as city_latitude ON city_latitude.user_id = usermeta.user_id AND city_latitude.meta_key = 'service_lat' 
    LEFT JOIN wp_usermeta as service_name ON service_name.user_id = usermeta.user_id AND service_name.meta_key = 'service_name' 
    LEFT JOIN wp_usermeta as service_category ON service_category.user_id = usermeta.user_id AND service_category.meta_key = 'service_category' 
    LEFT JOIN wp_usermeta as service_address ON service_address.user_id = usermeta.user_id AND service_address.meta_key = 'service_address' 
    LEFT JOIN wp_usermeta as service_level ON service_level.user_id = usermeta.user_id AND service_level.meta_key = 'wp_user_level' 
    LEFT JOIN wp_usermeta as service_info ON service_info.user_id = usermeta.user_id AND service_info.meta_key = 'service_additional' 
    LEFT JOIN wp_usermeta as service_area ON service_area.user_id = usermeta.user_id AND service_area.meta_key = 'service_area' 
    LEFT JOIN wp_usermeta as service_active ON service_active.user_id = usermeta.user_id AND service_active.meta_key = 'active' 
    LEFT JOIN wp_usermeta as service_keyword ON service_keyword.user_id = usermeta.user_id AND service_keyword.meta_key = 'service_keywords' 
    INNER JOIN wp_users ON wp_users.ID = usermeta.user_id 
WHERE (service_name.meta_value != '' AND service_name.meta_value != 'Anonymous') AND service_level.meta_value = 0 AND service_active.meta_value = 1 
HAVING distance < $search_distance 
ORDER BY distance ASC 
+3

Что EXPLAIN дает? Пожалуйста, покажите нам это. Есть ли какие-либо объединения, требующие полного сканирования таблицы? И вам нужно добавить условия WHERE к соответствующим компонентам ON! – Seb

+0

@P Heron - можете ли вы опубликовать созданные из таблицы данные с определенной датой выборки. Нет необходимости вступать в wp_usermeta более одного раза. Я отправлю вам запрос, если вы отправите некоторые данные в http: // sqlfiddle.com/ –

+0

@ Бернд Буффен - Это было бы здорово. Я установил некоторые данные в [link] (http://sqlfiddle.com/#!9/af672a). Я никогда не использовал это до того, как так модно его ок –

ответ

0

вы можете попробовать это. если вы пришлете мне больше данных, я могу более оптимизировать запрос для скорости. Вы должны изменить расчет с расстояния. У меня есть заменить значения PHP с константной (2) для тестирования, а также удалить замечание на линии, имеющей

SELECT 
    res.* 
    ,((ACOS(SIN(2 * PI()/180) * SIN(cityLat * PI()/180) 
    + COS(2 * PI()/180) * COS(cityLat * PI()/180) 
    * COS((2 - cityLong) * PI()/180)) * 180/PI()) * 60 * 1.1515) AS distance 
    FROM (
     SELECT 
      wpu.ID 
      , wpu.user_email 
      , GROUP_CONCAT(if(wpm.meta_key = 'service_lat'   ,wpm.meta_value,'') SEPARATOR '') AS cityLat 
      , GROUP_CONCAT(if(wpm.meta_key = 'service_long'   ,wpm.meta_value,'') SEPARATOR '') AS cityLong 
      , GROUP_CONCAT(if(wpm.meta_key = 'service_name'   ,wpm.meta_value,'') SEPARATOR '') AS service_name 
      , GROUP_CONCAT(if(wpm.meta_key = 'service_address'  ,wpm.meta_value,'') SEPARATOR '') AS service_address 
      , GROUP_CONCAT(if(wpm.meta_key = 'service_category'  ,wpm.meta_value,'') SEPARATOR '') AS service_category 
      , GROUP_CONCAT(if(wpm.meta_key = 'wp_user_level'   ,wpm.meta_value,'') SEPARATOR '') AS service_level 
      , GROUP_CONCAT(if(wpm.meta_key = 'service_additional' ,wpm.meta_value,'') SEPARATOR '') AS service_info 
      , GROUP_CONCAT(if(wpm.meta_key = 'service_area'   ,wpm.meta_value,'') SEPARATOR '') AS service_area 
      , GROUP_CONCAT(if(wpm.meta_key = 'active'     ,wpm.meta_value,'') SEPARATOR '') AS service_active 
      , GROUP_CONCAT(if(wpm.meta_key = 'service_keywords'  ,wpm.meta_value,'') SEPARATOR '') AS service_keyword 
    FROM wp_users AS wpu 
    LEFT JOIN wp_usermeta as wpm ON wpm.user_id = wpu.id  
    GROUP BY wpm.user_id 
) as res 
WHERE 
    (res.service_name != '' AND res.service_name != 'Anonymous') 
    AND res.service_level = 0 
    AND res.service_active = 1 
-- HAVING distance < $search_distance 
ORDER BY distance ASC; 

результат

ID user_email meta_key cityLat cityLong service_name service_address service_category service_level service_info service_area service_active service_keyword distance 
2 [email protected] wp_user_level 54.90131 -1.385126 service2 7 address1 address2 Support Info and Advice|Health and Wellbeing|Things to do|Education Training|Volunteering 0 A strong, local, independent charity working with and for older people (those 50+) Sunderland 1  3659.9253142487732 
3 [email protected] wp_user_level 54.897923 -1.514989 service 3 6 address1 address2 Support Info and Advice|Children Young people and Families|Health and Wellbeing|Things to do|Housing and your home|Education Training|Employment|Volunteering|Money Matters|Mental Health|Cultural 0 is a local independent charity offering a range of mental health and wellbeing services and training for the local community throughout . Sunderland 1  3660.080614342941 
+0

Большое спасибо, я дам ему попробовать и дам вам знать, как это происходит. –

+0

Он работал даже лучше, чем я ожидал, запрос до 0.09 секунд или около того. Спасибо еще раз за помощь. –

0

Я думаю, что ваш запрос довольно большой. В wordpress я не уверен, если вы можете разбить его на более мелкие части, а затем объединить его результаты.

Если вы хотите сохранить этот запрос, я предлагаю: 1) вы проверяете, что необходимые столбцы, на которых вы работаете, имеют индекс на них. 2) необходимые столбцы, которые указаны в индексе where.

Необходимые столбцы: вы можете поместить индекс во все столбцы в join и где, но это уменьшит скорость вставки. , поэтому вы можете попробовать поставить индекс на столбец, который принадлежит огромной таблице.

1

Вам нужно добавить условия, непосредственно в части ON. В противном случае вы сначала присоединитесь к чему угодно (что огромно), а затем уменьшите его. Таким образом, вы можете уменьшить его при подключении. Шоуд будет намного быстрее.

LEFT JOIN wp_usermeta as city_longitude ON city_latitude.user_id = city_longitude.user_id AND city_longitude.meta_key = 'service_long' 

и так далее

+0

Я не думаю, что это верно в MySQL. Условия в соединении оптимизируются так же, как условия в предложении 'WHERE'. Верно то, что помещение условия в предложение WHERE неявно превращает 'LEFT JOIN' в' INNER JOIN', но я думаю, что это может быть в порядке для вопроса OP. –