如何通过邮政编码 store/query 用户元数据
How to store/query users meta-data by zip code
我有一个复杂的问题,但我没有详细说明,而是将其简化为以下内容。
假设我们正在尝试构建一个系统,该系统的用户可以在每个邮政编码的基础上申请各种服务的优先级。该系统将有四个 table 像这样...
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 个邮政编码、几百个服务和几千个用户,对于同一邮政编码中的同一服务,任何用户都不能拥有与另一用户相同的优先级。
我需要一个查询,如果给定一个特定的邮政编码、半径、服务和 user_id 将 return 该服务半径内所有其他邮政编码的最高可用优先级.
而且,还想知道有关重组此数据的任何建议。
我在这里看到的问题是随着用户群的增长,service_priority table 会变得很大,理论上每个用户都会增加 45000 行,尽管实际上可能只有 10000 行行更大。
我可以做些什么来缓解这些问题?
切换到 InnoDB。
zip_code
table 可能应该有 PRIMARY KEY(zip)
除非你真的想要一个给定的 zip 的多行。
"no user can have the same priority level as another user for the same service in the same zip code" -- 可以由
强制执行
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
备注:
- 上面的索引也是为这个查询量身定做的。
- 最里面的查询得到一个 lat/lng 作为中心点。
- 中间查询侧重于查找附近的 zips。查看我添加的标签以找到许多问题讨论如何做到这一点。
- 外部查询然后根据用户和服务过滤结果。
- 最后,选择优先级最高的行。
我有一个复杂的问题,但我没有详细说明,而是将其简化为以下内容。
假设我们正在尝试构建一个系统,该系统的用户可以在每个邮政编码的基础上申请各种服务的优先级。该系统将有四个 table 像这样...
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 个邮政编码、几百个服务和几千个用户,对于同一邮政编码中的同一服务,任何用户都不能拥有与另一用户相同的优先级。
我需要一个查询,如果给定一个特定的邮政编码、半径、服务和 user_id 将 return 该服务半径内所有其他邮政编码的最高可用优先级.
而且,还想知道有关重组此数据的任何建议。
我在这里看到的问题是随着用户群的增长,service_priority table 会变得很大,理论上每个用户都会增加 45000 行,尽管实际上可能只有 10000 行行更大。
我可以做些什么来缓解这些问题?
切换到 InnoDB。
zip_code
table 可能应该有 PRIMARY KEY(zip)
除非你真的想要一个给定的 zip 的多行。
"no user can have the same priority level as another user for the same service in the same zip code" -- 可以由
强制执行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
备注:
- 上面的索引也是为这个查询量身定做的。
- 最里面的查询得到一个 lat/lng 作为中心点。
- 中间查询侧重于查找附近的 zips。查看我添加的标签以找到许多问题讨论如何做到这一点。
- 外部查询然后根据用户和服务过滤结果。
- 最后,选择优先级最高的行。