从Postcode DB获取lat / lng,并在PHP / MYSQL中按最接近的顺序排序

时间:2015-10-13 08:35:13

标签: php mysql geocoding latitude-longitude

我正在使用PHP和MYSQL建立一个网站。

我想先按最近的位置点我的搜索结果。我有一个物品表和一个交易表。我需要搜索这些表中的项目/交易位置,然后将位置与我的邮政编码数据库进行比较,并从相应的数据库条目中获取纬度和经度并对结果进行排序。我正在使用PDO准备好的语句。

我的数据库中有3个表。邮政编码,交易和项目。

邮政编码

| postcode | lat | lng |

DEALS

| id | title | location |

| id | title | location |

这是我的SQL ......

SELECT SQL_CALC_FOUND_ROWS *
FROM (
    SELECT *
    FROM items
      UNION
    SELECT * FROM deals
) AS allitemsdeals
INNER JOIN (
    SELECT
        postcodes.*,
        (3959 * acos(cos(radians(custom.lat)) * cos(radians(postcodes.lat)) * cos(radians(custom.lng) - radians(postcodes.lng)) + sin(radians(custom.lat)) * sin(radians(postcodes.lat)))
        ) AS distance
    FROM postcodes
    INNER JOIN postcodes AS custom
    WHERE custom.postcode = ?
) postcodes ON allitemsdeals.location = postcodes.postcode
HAVING distance < 5 ORDER BY id LIMIT ? OFFSET ?

我在加入此问题时遇到了问题。查询有效,但大约需要一分钟! :(

任何帮助将不胜感激!谢谢! :)

1 个答案:

答案 0 :(得分:0)

子查询正在扼杀您的表现。尝试在EXPLAIN上预先SELECT并查看输出 - 我怀疑有很多USING FILESORTUSING (NULL) INDEX内容。并检查了很多记录。可能还有一些derived表......

所有这些JOIN (SELECT ...语句都会导致查询运行,结果被缓存(或者更糟糕的是仍然为JOIN左侧的每个记录重新运行)而没有任何索引 - 以及所有内容狠狠地停下来。

最后SQL_CALC_FOUND_ROWS - 如果你不必这样做,就不要这样做。在应用LIMIT之前,它会导致MySQL计算所有行并处理所有行以计算它们。即使在LIMIT之前,您最好还是尽可能地减少的结果,最好不要使用SQL_CALC_FOUND_ROWS。 (单独的SELECT COUNT(1)会更好,相信我。去过那里。)

解决方案?不容易。首先更改您的架构。

首先:我将&#34;交易&#34;结合起来和&#34;项目&#34;进入一个大表 - 使用一列来区分类型(除非有很多其他列我没有看到),因为UNION很可能(或肯定?)杀死任何索引你有

第二次:距离的子查询 - 哦,不!这应该是用于计算最大距离的直接WHERE子句。如果你愿意,我会尝试优化它 - 但是如果没有SQLfiddle.com或其他东西可以玩,那么在我的空闲时间开始复制你的架构和数据有点多了。 (如果你用它设置了一个SQLfiddle - 我很高兴有一个戳。)

第三:我考虑使用MySQL的空间功能再次使用long / lat数据。有很多可用的文档:

这是一些很酷的东西 - 我希望在很长一段时间内(付费!)小时内找借口玩这种数据。我很想知道你最终会找到什么解决方案。

正如我所说 - 如果你提供一个SQLfiddle(假设其他人没有先提供更好的解决方案),我至少会高兴地看一下接下来的72小时。