优化/ MySQL 查询
Optimizing/ MySQL query
我是 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
我认为您的查询非常庞大。在 wordpress 中,我不确定你是否可以将它分解成更小的部分,然后组合它的结果。
如果你想保留这个查询,我建议 1) 检查你正在执行连接的必要列是否有索引 2) where 子句中的必要列被索引。
必要的列:您实际上可以在 join 和 where 中的所有列上放置索引,但这会降低插入速度。
所以您可以尝试将索引放在属于 table 的列上,这些列很大。
您需要直接在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'
等等
你可以试试这个。如果您向我发送更多数据,我可以进一步优化查询
为了速度。您必须从距离修改计算。我已将 PHP 值替换为 const (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 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
我是 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
我认为您的查询非常庞大。在 wordpress 中,我不确定你是否可以将它分解成更小的部分,然后组合它的结果。
如果你想保留这个查询,我建议 1) 检查你正在执行连接的必要列是否有索引 2) where 子句中的必要列被索引。
必要的列:您实际上可以在 join 和 where 中的所有列上放置索引,但这会降低插入速度。 所以您可以尝试将索引放在属于 table 的列上,这些列很大。
您需要直接在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'
等等
你可以试试这个。如果您向我发送更多数据,我可以进一步优化查询 为了速度。您必须从距离修改计算。我已将 PHP 值替换为 const (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 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