1

我有一个系统,它将从数据库中返回所有用户,并按与参考邮政编码的最短距离对结果进行排序。

例如:用户将来到网站,输入邮政编码,它将返回所有其他离他的邮政编码最近的用户(升序)

我现在怎么做,为什么会出现问题?

该系统包含超过 3000 万用户及其邮政编码。我正在检索特定州和城市的所有用户(将数据集缩小到大约 10,000)。

这就是问题实际发生的地方。现在,mysql (10,000) 行发送到 PHP 的所有结果都被发送到邮政编码计算器库,该库计算基本邮政编码和用户邮政编码之间的距离 - 10,000 次。然后按最近的邮政编码对结果进行排序。

如您所见,这是非常糟糕的优化代码。并且这 10,000 条记录循环了两次。更不用说每个 httpd 进程仅在 mysql 之间传输数据所需的 RAM 量。

我想问这里的大师,无论如何优化这个?

我有一些自己的想法,但我不确定它们的效率如何。

尝试在 mysql 本身中进行所有邮政编码的计算和排序,并返回分页的行数。为此,我需要将邮政编码计算逻辑之间的距离移动到存储过程。这样我就可以防止在 PHP 中处理 10,000 条记录。但是,仍然存在一个问题。我不需要计算已经计算的邮政编码的距离(对于具有相同邮政编码的 2 个用户)。

其次,如何使用存储过程对 mysql 中的行进行排序?

你们有什么感想 ?这是一个好方法吗?我可以期待使用它来提升性能吗?你有什么其他的建议 ?

我知道这个问题很大,我非常感谢您花时间阅读到最后。我真的很想听听您对此的看法。

4

3 回答 3

1

由于我对 PHP 或 MySQL 不太熟悉,我只能提供一些基本提示,但它们应该会有所帮助。这还假设您没有直接与 MySQL 的 zip 库交互的方法。

首先,由于您怀疑您在一个城市中有 10k 个邮政编码,因此请使用您现有的查询并执行类似的操作

SELECT DISTINCT ZipCode FROM Users WHERE ...

这可能最多返回几十个邮政编码,并且没有重复。通过您的邮政编码库运行它。该库本身可能是缓慢的原因,因为它必须查找邮政编码,并进行一系列花哨的三角操作才能获得实际距离。获取此结果,并将其插入到临时表中,其中仅包含邮政编码和距离。

完成该列表后,进行另一个查询,获取您想要的其余用户数据,然后加入邮政编码的临时表中以获取您的距离。

这应该会给你很大的加速。在计算结果后,您可以在第二个查询中执行您需要的任何分页。并且不再循环遍历 10k 行。

于 2011-03-06T22:07:25.383 回答
1

我建议您在计算准确距离以进行过滤和排序之前缩小纬度和经度范围。

我的意思是,如果您进行全表扫描并计算数据库中所有邮政编码相对于您的参考点的距离,这将非常慢。

相反,按邻近度过滤邮政编码。我的意思是如果你有纬度 10 和经度 20,首先计算你想要的接近度的最大角度范围。假设您想要 10 英里的接近范围。这可能转化为 0.15 度。所以你需要过滤你的邮政编码首先纬度在 10-0.15 和 10+0.15 之间,经度在 20-0.15 和 20+0.15 之间。

只有在那之后,您才能在 SQL 查询条件中包含准确的距离子句。这会快得多,因为您不再进行全扫描,并且您最终可以在经度和纬度字段上使用范围索引。

要将英里转换为度,请记住,地球的周长约为 25,000 英里,将 25000 除以 360 度,即每度 70 英里。如果您想要 10 英里的范围,则您的度数范围最多为 0.15 度。

请记住,这些计算并不准确(地球并不是完全圆整的),但这并不重要。重要的是您找到一个高于真正准确值的度数范围值。

于 2011-03-06T22:11:56.307 回答
0

如果您可以将所有邮政编码的纬度和经度获取到 MySQL 中,或者有一种简单的方法来获取基本邮政编码的纬度/经度并将其输入到 MySQL 查询中,那么您可以在 MySQL 中按距离对 10k 用户进行排序。这里有一个非常相似的问题和答案,它为您提供了距离函数的正确数学。您可能还想研究Mysql 空间扩展,它可以让您将纬度/经度插入和索引为 2D POINT 数据。

于 2011-03-06T21:56:30.540 回答