2017-02-22 86 views
-1

我有一个复杂的问题,但没有进入具体细节我已简化为以下内容。如何通过邮政编码存储/查询用户元数据

假设我们正在尝试构建一个系统,系统的用户可以在每个邮政编码的基础上申请各种服务的优先级。该系统将有四个表是这样的...

CREATE TABLE `zip_code` (
    `zip` varchar(7) NOT NULL DEFAULT '', 
    `lat` float NOT NULL DEFAULT '0', 
    `long` float NOT NULL DEFAULT '0' 
    PRIMARY KEY (`zip`,`lat`,`long`), 
) ENGINE=MyISAM DEFAULT CHARSET=latin1; 

CREATE TABLE `user` (
    `user_id` int(10) NOT NULL AUTO_INCREMENT 
) ENGINE=MyISAM DEFAULT CHARSET=latin1; 

CREATE TABLE `service` (
    `service_id` int(10) NOT NULL AUTO_INCREMENT 
) ENGINE=MyISAM DEFAULT CHARSET=latin1; 

CREATE TABLE `service_priority` (
    `user_id` int(10) NOT NULL', 
    `service_id` int(10) NOT NULL', 
    `zip` varchar(7) NOT NULL, 
    `priority` tinyint(1) NOT NULL 
) ENGINE=MyISAM DEFAULT CHARSET=latin1; 

现在让我们也说,我们有45000拉链码,几百服务和几千个用户,没有用户可以具有相同的优先级作为同一邮政编码中同一服务的另一个用户。

我需要一个查询,如果给定一个特定的邮政编码,radius,service和user_id将返回该服务在该半径内的所有其他邮政编码的最高可用优先级别。

此外,还想知道重组此数据的任何建议。

我看到这里发生的问题是随着用户群的增长,service_priority表会变得很大,理论上45000行对于每个用户来说都更大,尽管实际上可能只有10000行更大。

我能做些什么来缓解这些问题?

+1

邮政编码没有一个拉特/长,他们是多边形,所以我不知道这是如何工作。您可能会想要查看获取邮政编码信息的第三方数据库。您还需要使用空间类型而不是浮动。有[MySQL的空间扩展](https://dev.mysql.com/doc/refman/5.7/en/spatial-extensions.html)或更好的[PostgreSQL的GIS扩展](http://postgis.net/) 。或者查看使用第三方的任何位置服务。 – Schwern

+1

这听起来像是你在为每个zip使用一个头脑简单的质心? 45K听起来像美国邮政编码; 'VARCHAR(7)'听起来像是一个错误 - 应该是'CHAR(5)'?或者“中等(5)无标志ZEROFILL”。 –

+0

这些评论对我来说都是正确的。实际上我们只是使用邮编的中心点,因此我们的系统对于真实的邮编边界不会很准确。此外,它现在只是美国的拉链,但我们的DB也有加拿大的拉链,它们是字母数字。理论上我们有一天可能在加拿大做生意。只是现在学习空间扩展,谢谢。 –

回答

0

切换到InnoDB。

zip_code表应该可能有PRIMARY KEY(zip),除非你真的想要多行给定的zip。

“没有用户可以有相同的优先级作为其他用户在同一邮政编码相同的服务” - 可以通过

service_priority : UNIQUE(service_id, user_id, zip) 

强制执行然后您的查询可能看起来像

SELECT sp.* 
    FROM (SELECT b.zip 
      FROM (SELECT lat, lng FROM zip_code WHERE zip = '$zip') AS a 
      JOIN zip_code AS b 
      WHERE ... < $radius 
     ) AS z 
    JOIN service_priority AS sp 
    WHERE sp.zip = z.zip 
     AND sp.user_id = $user_id 
     AND sp.service_id = $service_id 
    ORDER BY sp.priority DESC 
    LIMIT 1 

注:

  • 索引,上方,也适合用于此查询。
  • 最内层查询获取中心点的一个纬度/经度。
  • 中间查询重点查找附近的拉链。看到我添加的标签,以找到许多问题讨论如何做到这一点。
  • 外部查询然后根据用户和服务过滤结果。
  • 最后,挑选最高优先级的行。