使用ORIN重写SQL子查询和ORDER ... LIMIT

时间:2014-01-30 10:25:17

标签: mysql sql

我有一个MySQL查询,根据用户的位置和区域边界将用户映射到区域:

UPDATE User u SET u.zoneId = (
   SELECT z.id FROM Zone z
   WHERE ST_Contains(z.boundary, u.location)
   ORDER BY z.level DESC
   LIMIT 1
);

这样可以正常工作,但由于它为每条记录执行子查询,所以速度很慢。

是否可以使用JOIN重写它,即使它在子查询中使用ORDER BY ... LIMIT 1

这个ORDER BY ... LIMIT 1是必需的,因为几个封装区域可以匹配一个位置,并且只能分配最小的一个(最高级别)。

1 个答案:

答案 0 :(得分:0)

在没有任何测试数据或完整DDL的情况下,我无法对此进行测试,但这可能会有效。使用连接和子查询,但是将子查询隐藏在额外的级别,这可能允许MySQL忽略他在子查询中使用要更新的表。

依赖于具有唯一键的用户表(我刚把它称为id)。

UPDATE User u 
INNER JOIN Zone z
ON ST_Contains(z.boundary, u.location)
INNER JOIN
(
    SELECT id, MaxLevel
    FROM
    (
        SELECT u.id, MAX(z.level) AS MaxLevel
        FROM User u 
        INNER JOIN Zone z
        ON ST_Contains(z.boundary, u.location)
        GROUP BY u.id
    ) Sub1
) Sub2
ON u.id = Sub2.id AND z.level = Sub2.MaxLevel
SET u.zoneId = z.id

如果你可以在SQL小提琴中设置一些测试数据,我可以测试一下。