【问题标题】:Most Efficient Way To Run A Query On PROCEDURE Results对 PROCEDURE 结果运行查询的最有效方法
【发布时间】:2014-07-16 11:51:42
【问题描述】:

感谢您的帮助。

我正在尝试对 MySQL PROCEDURE 生成的结果创建查询。最好,我想将此 PROCEDURE 修改为 JOIN 并在 1 个查询中完成所有操作,但从我一直在阅读的内容来看,这是不可能的,所以我寻找从同一数据库但不同表中查询信息的最有效方法,由目标 ID 链接。

eg:查询地址表,获取ID所链接的PROCEDURE的每个结果的每个地址

如果 PROCEDURE 返回 50 个不同的“目的地”或结果,有什么方法可以避免执行 50 个额外的查询?我假设最有效的方法是创建另一个过程。

PROCEDURE 代码 - 此过程查询数据库并根据纬度和经度获取点。数据由 MAXMIND 提供,可在此处找到:

https://www.maxmind.com/en/geolocation_landing

CREATE PROCEDURE `GEODIST`( IN userid int, IN dist int, IN olat float, IN olon float ) DETERMINISTIC READS SQL DATA

BEGIN
DECLARE mylon DOUBLE;
DECLARE mylat DOUBLE;
DECLARE lon1 FLOAT;
DECLARE lon2 FLOAT;
DECLARE lat1 FLOAT;
DECLARE lat2 FLOAT;

SET mylon = olon;
SET mylat = olat;
SET lon1 = mylon - dist / abs( cos( radians( mylat ) ) * 69 );
SET lon2 = mylon + dist / abs( cos( radians( mylat ) ) * 69 );
SET lat1 = mylat - ( dist / 69 );
SET lat2 = mylat + ( dist / 69 );

SELECT destination.id, destination.latitude, destination.longitude, 3956 * 2 * ASIN(SQRT( POWER(SIN((origin.latitude -destination.latitude) * pi()/180 / 2), 2) +COS(origin.latitude * pi()/180) * COS(destination.latitude * pi()/180) *POWER(SIN((origin.longitude -destination.longitude) * pi()/180 / 2), 2) )) AS distance FROM locations destination, locations origin WHERE origin.id = userid
AND destination.longitude BETWEEN lon1 AND lon2 AND destination.latitude BETWEEN lat1 and lat2 
HAVING distance < dist ORDER BY distance LIMIT 50;
END

调用过程:

CALL GEODIST( $userid, $distance, $latitude, $longitude )

编辑

目前,我已使用 cmets 部分的建议编辑了代码,但在尝试创建 PROCEDURE 时仍收到错误消息。我尝试为目的地和在本例中的照片表使用别名,但它引发了错误:

错误:

#1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'd, locations origin JOIN photos p ON d.id = p.lid WHERE origin.id = userid AND ' at line 18


CREATE PROCEDURE `GEODIST`( IN userid int, IN dist int, IN olat float, IN olon float ) DETERMINISTIC READS SQL DATA

BEGIN
DECLARE mylon DOUBLE;
DECLARE mylat DOUBLE;
DECLARE lon1 FLOAT;
DECLARE lon2 FLOAT;
DECLARE lat1 FLOAT;
DECLARE lat2 FLOAT;

SET mylon = olon;
SET mylat = olat;
SET lon1 = mylon - dist / abs( cos( radians( mylat ) ) * 69 );
SET lon2 = mylon + dist / abs( cos( radians( mylat ) ) * 69 );
SET lat1 = mylat - ( dist / 69 );
SET lat2 = mylat + ( dist / 69 );

SELECT d.id, d.name, d.address, d.latitude, d.longitude, d.category, d.type, p.lid, p.pid, 3956 * 2 * ASIN(SQRT( POWER(SIN((origin.latitude -d.latitude) * pi()/180 / 2), 2) +COS(origin.latitude * pi()/180) * COS(d.latitude * pi()/180) *POWER(SIN((origin.longitude -d.longitude) * pi()/180 / 2), 2) )) AS distance FROM locations d, locations origin JOIN photos p ON d.id = p.lid WHERE origin.id = userid
AND d.longitude BETWEEN lon1 AND lon2 AND d.latitude BETWEEN lat1 and lat2 
HAVING distance < dist ORDER BY distance LIMIT 50;
END

【问题讨论】:

    标签: php mysql performance stored-procedures procedure


    【解决方案1】:

    如果我正确理解您的问题,您就不能直接加入地址表吗?

    SELECT destination.id, destination.latitude, destination.longitude, 
    3956 * 2 * ASIN(SQRT( POWER(SIN((origin.latitude -destination.latitude) * pi()/180 / 2), 2) +COS(origin.latitude * pi()/180) * COS(destination.latitude * pi()/180) *POWER(SIN((origin.longitude -destination.longitude) * pi()/180 / 2), 2) )) 
    AS distance 
    FROM 
    locations destination, 
    locations origin,
    LEFT JOIN
    addressTable
    ON addressTable.id = destination.id
    WHERE 
    origin.id = userid
    AND destination.longitude BETWEEN lon1 AND lon2 
    AND destination.latitude BETWEEN lat1 and lat2
    HAVING distance < dist 
    ORDER BY distance LIMIT 50;
    

    没有数据很难测试,但我相信就是这样。

    为作者编辑编辑

    在您的新代码中,您替换以下内容:

    FROM locations d, locations origin 
    JOIN photos p ON d.id = p.lid 
    

    您要从中提取的表的适当名称应该是这样的:

    FROM destination d, origin o,
    JOIN photos p
    ON d.id = p.lid
    

    当我们使用别名时,我们只是说从表“目标”中选择一些东西,但我们将其命名为“d”,这样我们就没有很长的 sql 语句。

    此外,在您想要的选择中使用与 FROM 子句中使用的相同的别名。例如:

    SELECT destination.id, destination.latitude
    

    应该是

    SELECT d.id, d.latitude
    

    【讨论】:

    • 从我一直在阅读的内容来看,您不能在 MYSQL 过程中使用连接,但我会试试这个,我试图添加一个 JOIN,但 MySQL 在尝试插入加入代码,我会尽快回复您。谢谢我非常感谢任何帮助!
    • 查询如何指定在地址表上查询什么?
    • 您必须在 SELECT 语句中添加它。所以它将是 sql 的选择部分中的 yourAddressTableName.columnName 。在这里使用别名以避免混淆可能会有所帮助。例如 FROM 位置目标 d,位置起点 o,LEFT JOIN 位置地址表 a。因此,允许您在其他地方使用点语法。例如,它将是 d.id 而不是 destination.id
    • 这次在过程中加入JOIN并没有报错,(我猜是JOIN代码的放置),但是尝试运行它返回的查询:#1054 - 未知'on 子句'中的'destination.id'列,我以前从未遇到过查询问题,我不确定这个错误意味着什么,除了它正在寻找地址表中的destination.id 列?跨度>
    • 让我试试这个,感谢您的意见和帮助,非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-01
    • 1970-01-01
    • 2014-10-20
    • 2018-10-22
    • 2021-04-07
    • 1970-01-01
    • 2011-03-22
    相关资源
    最近更新 更多