Php 优化复杂的SQL查询
我在我的Symfony2站点上使用了以下查询,用于定位距离地图上给定点最近的纬度和经度对。有一个表“latlong”存储这些对,还有一个表“fos_user_user”存储用户,还有一个“usermeta”表存储关于这些用户的数据(这是我们从wordpress移动所有数据时的遗留问题)。问题是它运行得非常慢——当我们在旧的WordPress站点上运行一个非常简单的查询时,它通常相当快。有人知道如何优化它吗Php 优化复杂的SQL查询,php,mysql,sql,symfony,doctrine,Php,Mysql,Sql,Symfony,Doctrine,我在我的Symfony2站点上使用了以下查询,用于定位距离地图上给定点最近的纬度和经度对。有一个表“latlong”存储这些对,还有一个表“fos_user_user”存储用户,还有一个“usermeta”表存储关于这些用户的数据(这是我们从wordpress移动所有数据时的遗留问题)。问题是它运行得非常慢——当我们在旧的WordPress站点上运行一个非常简单的查询时,它通常相当快。有人知道如何优化它吗 SELECT latlong.user AS id, fos_user_use
SELECT
latlong.user AS id,
fos_user_user.username AS username,
latlong.lat AS lat,
latlong.lng AS lng,
fos_user_user.email_canonical AS email,
firstname.VALUE AS firstname,
lastname.VALUE AS lastname,
address1.VALUE AS address1,
address2.VALUE AS address2,
address3.VALUE AS address3,
postcode.VALUE AS postcode,
image.VALUE AS image,
(
3959 * ACOS(
COS(
RADIANS('51.4424728')
) * COS(
RADIANS(lat)
) * COS(
RADIANS(lng) - RADIANS('7.2586558')
) + SIN(
RADIANS('51.4424728')
) * SIN(
RADIANS(lat)
)
)
) AS distance
FROM
latlong
JOIN fos_user_user ON latlong.user = fos_user_user.id
LEFT JOIN usermeta AS firstname ON firstname.user_id = latlong.user
AND firstname.field_id = '15'
LEFT JOIN usermeta AS lastname ON lastname.user_id = latlong.user
AND lastname.field_id = '16'
LEFT JOIN usermeta AS image ON image.user_id = latlong.user
AND image.field_id = '11'
LEFT JOIN usermeta AS address1 ON address1.user_id = latlong.user
AND address1.field_id = '2'
LEFT JOIN usermeta AS address2 ON address1.user_id = latlong.user
AND address1.field_id = '3'
LEFT JOIN usermeta AS address3 ON address1.user_id = latlong.user
AND address1.field_id = '4'
LEFT JOIN usermeta AS postcode ON postcode.user_id = latlong.user
AND postcode.field_id = '5'
LEFT JOIN usermeta AS public ON public.user_id = latlong.user
AND public.field_id = '10'
WHERE
public.value = 'YES'
HAVING
distance < 25
ORDER BY
distance ASC
LIMIT
0, 5
选择
latlong.user作为id,
fos_user_user.username作为用户名,
latlong.lat作为lat,
latlong.lng作为液化天然气,
fos_user_user.email_标准电子邮件,
firstname.VALUE作为firstname,
lastname.VALUE作为lastname,
address1.VALUE作为address1,
address2.VALUE作为address2,
address3.VALUE作为address3,
postcode.VALUE作为邮政编码,
图像。作为图像的值,
(
3959*ACOS(
因为(
弧度('51.4424728')
)*COS(
弧度(纬度)
)*COS(
弧度(lng)-弧度('7.2586558')
)+罪(
弧度('51.4424728')
)*罪(
弧度(纬度)
)
)
)作为距离
从…起
拉特朗
在latlong.user=fos\u user\u user.id上加入fos\u user\u user
在firstname.user\u id=latlong.user上将usermeta作为firstname左连接
firstname.field_id='15'
在lastname.user\u id=latlong.user上将usermeta作为lastname左连接
lastname.field_id='16'
在image.user\u id=latlong.user上将usermeta作为图像左连接
和image.field_id='11'
在address1.user\u id=latlong.user上将usermeta作为address1左连接
和地址1.field_id='2'
在address1.user\u id=latlong.user上将usermeta作为address2左连接
地址1.field_id='3'
在address1.user\u id=latlong.user上将usermeta作为address3左连接
地址1.field_id='4'
在postcode.user\u id=latlong.user上将usermeta作为邮政编码左连接
和postcode.field_id='5'
在public.user\u id=latlong.user上将usermeta作为public左连接
和public.field_id='10'
哪里
public.value='YES'
有
距离<25
订购人
距离ASC
限度
0, 5
表格结构<代码>解释?糟糕的数据库设计。您知道public.value='YES'使最后一个左连接作为内部连接执行的位置吗?(将条件移动到ON子句以作为左连接执行。)通常对于聚合函数,将该条件移动到WHERE。(MySQL扩展以允许列在那里…)您需要更强大的功能。在这种情况下,mysql必须计算到所有用户的距离(所有这些连接)。感谢您的评论,共有3个表涉及fos_user_user(用户表)、usermeta(包含3列的meta values表、user_id、field_id和value-基本上是EAV中的values表),latlong-这有纬度和经度对,还有一个用户ID@jarlh-你能举个例子说明如何将public.value=10条件与ON子句结合起来吗?