2015-10-13 79 views
3

我正在用PHP和MYSQL构建一个网站。从邮政编码数据库获取纬度/经度,并在PHP/MYSQL中以最接近的顺序排列

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

我在我的数据库中有3个表。邮编,交易和物品。

邮政编码

| postcode | lat | lng | 

特价

| id | title | location | 

ITEMS

| 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 ? 

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

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

+0

ST_Within可能会加快速度,但没有看看你的解释输出这是猜测工作。请更新您的问题,而不是发布PHP,发布实际得到执行的SQL查询。并且还指出你的表是什么样的,他们的行数是多少 – e4c5

+0

感谢您的回复。这个问题已经用例子更新了。 :) – Goldberg

+0

仍然需要解释输出。 – e4c5

回答

0

子查询正在杀死你的表现。尝试在您的SELECT上预先输入EXPLAIN并查看输出 - 我怀疑有很多USING FILESORTUSING (NULL) INDEX的东西。并检查了很多记录。也许有些derived表太...

所有这些JOIN (SELECT ...语句导致查询运行,结果被缓存(或者更糟的是重新跑在JOIN左侧的每个记录),没有任何索引 - 和一切都变成了可怕的停顿。

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

解决方法?不容易。从改变你的模式开始。

首先:我会结合“交易”和“物品”合并为一个大表 - 使用列区分类型的(除非有很多其他列的,我没有得到的可见性),因为UNION会可能(或绝对?)杀死你拥有的任何索引。

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

第三:我会考虑使用MySQL的空间功能重新开始long/lat数据。有大量的文件可供选择:

这是一些很酷的东西 - 数据的类型,我想有一个借口打在(付费!)小时内我自己很长一段时间。我很想看看你最终会得到什么解决方案。

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

+0

很好的答案。但我认为大多数的'最快的方式找到...'你已经被取代st_within的答案' – e4c5

+0

找到5最近的“最快”的方式不能使用一个简单的索引 - 你坚持一个完整的表格扫描,或者也许是一维扫描(例如,......和......之间的拉特)。要快速查找任意大的数据集,请参阅http://mysql.rjweb.org/doc.php/latlng。 –