优化/ MySQL查询

时间:2016-11-28 16:20:32

标签: mysql wordpress entity-attribute-value

我是MySQL的新手,并且一直致力于以下查询从wordpress users / usermeta表中提取值列表。该查询除了性能之外还很糟糕,我不确定如何改进它。

查询需要12秒以上才能完成,只有400个左右的用户,如果添加更多内容,这将成为一个巨大的问题。

我注意到MySQL报告没有唯一的列,但我不知道如何解决这个问题,因为用户ID已经是结果的一部分。

这是默认查询,完整查询使用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 个答案:

答案 0 :(得分:1)

您需要直接在ON部分添加where条件。否则你将首先加入任何东西(这是巨大的),然后减少它。所以你可以在加入时直接减少它。应该快得多。

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

等等

答案 1 :(得分:0)

我认为您的查询非常庞大。在wordpress中,我不确定你是否可以将它分成更小的部分然后结合其结果。

如果你想保留这个查询,我建议1)你检查你正在进行连接的必要列是否有索引2)where子句中的必要列被索引。

必要的列:您实际上可以在连接中的所有列上放置索引,但它会降低插入速度。 所以你可以尝试将索引放在属于巨大的表的列上。

答案 2 :(得分:0)

你可以试试这个。如果你发给我更多数据,我可以更优化查询 速度。您必须从距离修改计算。我已用const(2)替换PHP值进行测试,并删除有行的备注

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   email2@outlook.com  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   email3@outlook.com  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