第一个设计可能是最紧凑的;可以通过在start
和上添加跨越索引来优化它end
。您还可以像这样组合两种付款方式:
zipcodes
start(int) | end(int) | carrier(fk::carried.id) | cod (0, 1) | prepaid (0, 1)
该carrier
字段是可选的,但您可以稍后在需要更新一个运营商的邮政编码范围时使用它。
不要试图变得聪明,根据是否cod
和prepaid
可用将范围合并在一起;您可以输入具有不同运营商和付款类型可用性的多个范围。要查询它们,您将使用:
SELECT COUNT(cod), COUNT(prepaid)
FROM zipcodes
WHERE start <= :start AND :end <= end
cod
这将给出包含特定邮政编码和/或特定邮政编码的单行prepaid
(即使它可能匹配多个数据库行。
当承运人更改其邮政编码范围和付款可用性时,最简单的方法是删除该承运人的所有行并重新填充(使用表锁);如果您决定保留该数据库字段,这对您来说非常容易。
您的第二个设计看起来更像是您从运营商那里接收邮政编码列表的方式,并且管理更加简化。不过,我会再次将它们放在一张桌子上:
zipcodes
zipcode | cod (0, 1) | prepaid(0, 1)
By choosing ENUM
datatype you can get pretty good data compression as well. Updating this table when a carrier changes their delivery data is less trivial, because the carrier
field is missing, so that means you have to eitherwrite a script that detects the addition, deletion and updates of a particular zip code or start over completely with both carrier data.
If updates are rare and you don't mind taking the whole table down when it does happen, I would recommend the second option. By adding cod
and prepaid
types in each row rather than two separate tables you can use a primary key for faster lookups compared to the range solution.
If you like flexibility and the fact that you can tell which carrier is supported on a particular range I would go for the first option; the index is still fast enough for most cases and the table size is likely comparably with the second option.