【问题标题】:Storing pincodes and shipping charge for each pincode存储密码和每个密码的运费
【发布时间】:2016-05-26 11:51:16
【问题描述】:

我正在使用 Magento 创建一个电子商务应用程序。我需要为此构建一个自定义运输模块。目前我正在设计表格来存储数据。

问题是当客户下订单时,我需要联系在该地点提供服务的运输公司,即取货和送货。一旦我获得了运输公司的详细信息,我需要向该特定地点收取运费。我问了一个关于如何存储密码和运输公司detail 的问题。

我得到的建议是创建一个如下表

    Shipping Companies
    --------
    ID (int, PK)
    Name (string)

    Pincodes
    --------
    ID (int, PK)
    Pincode (string)

    These entities have a many-to-many relationship.  So create a table to link them:

    Shipping Company Pincodes
    --------
    ID (int, PK)
    Shipping Company ID (int, FK)
    Pincode ID (int, FK)
    Pickup (bit)
    Delivery (bit)

使用此表结构,我可以跟踪将提供取件和交付的运输公司。但是,一旦我有了这些运输公司 ID,我需要做的下一步就是收取运费以在该地点交付产品。我的一位同事提出的一个建议是存储密码范围,而不是存储所有密码。并且 row 将存储多个运输公司的费率 例如:

Pincode   |  Fedex Rate   |   DHL Rate  |  UPS Rate
----------------------------------------------------
67 - 69        7.7              6.5          5.5 

但由于我存储了一系列密码,我将如何识别运输公司是否不提供该范围内任何密码的送货或取货服务。还有其他更好的方法来存储密码的运费。实际上有大约 19000 多个密码。我想为每个密码和运输公司存储单独的费率,但这会使表格变得非常大。

【问题讨论】:

  • “不提供”——听起来对NULL很有用。
  • 你需要一张“从'这里'到任何地方”的表格吗?还是一张“从anywhereanywhere”的表格?
  • 19000 行是“小”,而不是“大”。如果它被正确索引(PRIMARY KEY(pin)),性能会非常好。
  • 我的意思是对于一家运输公司来说,会有 19000 行,比如 pincode_id shipping_company_id 费率。至少会有 4 家航运公司。
  • 使用 19K 行。加载更复杂,但查询速度非常快。

标签: mysql database-design


【解决方案1】:

数万行对于 MySQL/MariaDB 来说很小。我会放弃Pincodes 表以及Shipping Company Pincodes 表中的代理ID 并使用Shipping Company IDPincode 作为复合主键。 Pincode 看起来像一个整数(效率不低于代理 id)和一个有意义的自然(外部定义)键,这意味着您可能会在查询中经常需要它。如果它构成您的主键的一部分,则默认情况下它可以方便地使用和索引。我还会在此表中添加一个Rate 列。

总结一下:

Shipping Companies
--------
ID (int, PK)
Name (string)

Shipping Company Pincodes 
--------
Shipping Company ID (int, PK/FK)
Pincode (int, PK/FK)
Pickup (bit)
Delivery (bit)
Rate (decimal)

【讨论】:

  • 但是,想要的表不需要19000*19000/2行吗?
  • 与其记录所有密码组合,或许可以将这个表与自身连接起来以得出相同的信息。
  • 但是价格不是取决于源引脚和目的引脚吗?
  • 如果运营商数量不限,最好使用一个包含 4 列的更大表:target_pin、carrier_id、deliver_cost、receive_cost。 PK 将位于前 2 列。 3*160K 行仍然不是很大。 (由于不是所有的运营商都去所有的引脚,它会小于 3*160K。)
  • SELECT 将是 ... ORDER BY delivery_price DESC LIMIT 1。还是很有效率的。
【解决方案2】:

这解决了一个更复杂的问题,所以它并没有真正解决所问的问题。

主要查询是“公司从 Pin 12345 运送到 Pin 29876 的费用是多少?”

Plan A 是一个包含所有可能的开始/结束引脚的 3.6 亿行表。这可能是最好的,因为在拥有PRIMARY KEY(pin_from, pin_to) 的同时执行SELECT ... WHERE pin_from = $from AND pin_to = $to 非常有效。该表可能需要 20GB;那样可以么? SELECT 通常可能需要 10 毫秒。

Plan B,你提到的,需要一张像

这样的桌子
CREATE TABLE Rates (
    from_a, from_z,   -- min and max pins for source pin range
    to_a, to_z,       -- ditto for destination
    fedex DECIMAL(6,2) NULL   -- NULLable in case fedex does not run that route
    etc.
    PRIMARY KEY(from_a, from_z, to_a, to_z)
) ENGINE=InnoDB;

桌子会小得多。查询类似于:

SELECT  IFNULL(fedex, 'N/A')  AS Fedex, ...
    FROM Rates
    WHERE $from BETWEEN from_a AND from_z
      AND $to   BETWEEN to_a   AND to_z;

问题是没有很好的方法来索引它。这会遇到两个问题——以这种方式在一个范围内进行测试是不可优化的,它本质上是一个二维问题。

如果表只有数千行,那么表扫描并不是“太糟糕”。如果是数百万行,可能会太慢。

加载表格将是很多具有挑战性的代码——您不希望有任何重叠的矩形。更新表格会更具挑战性。

C 计划...也许SPATIAL 索引正是您所需要的。空间“点”的 (x,y) 是对 (pin_from, pin_to)。抱歉,我不知道下一步该去哪里。

Plan D...这是Plan B的一个变种,但它大大提高了效率。它增加了 2 列; x,y。它们的值为 0..190,计算为 floor(pin/100)。这个想法是拥有 190*190 的“桶”。在每个桶中是每个在桶中有一个点的矩形(a la Plan B)。是的,这意味着一些矩形将出现在多个存储桶中;对于显着的性能改进来说,这是一个很小的代价。

PRIMARY KEY(x, y, from_a, from_z, to_a, to_z)

SELECT ...
    FROM Rates
    WHERE x = FLOOR($from/100)
      AND y = FLOOR($to/100)
      AND the rest of Plan B's WHERE

由于“桶”的行数不能超过 100*100,并且它们在表中是“聚集”的,因此扫描是合理有界的。如果说,平均桶是 10 针 x 10 针,那么平均桶只有 100 行——非常有效。

抱歉,加载和更新仍然很复杂。

(我选择 100x100 作为存储桶大小;根据典型矩形的大小,可能会有更好的选择。请注意 100 的优势:它导致 0..190 范围,允许 x 和 y 很小:一个 1 字节的 TINYINT UNSIGNED。)

【讨论】:

  • 非常感谢您提供如此详细的答复。是的,我正在寻找从 pincode 123 运送到 pincode 4566 的费用。我将不得不存储多个运营商(如 Fedex、UPS 等)的费用。我认为至少会有 4 个运营商。但目前我只使用来自联邦快递的数据。将来我也将不得不整合其他运营商。大约有 1,60,000 个密码。其中,联邦快递为大约 19,000 个地点提供服务。其中一些只提供送货服务。
  • 需要关于 A 计划的建议。与其保持所有可能的组合,不如保持范围组合?例如,考虑密码 676303,676387,6​​7642 和 695382,695381,695650。对于密码 676303,有 6 种可能的组合。但是如果取密码的前三个数字,即 676 - 676 和 676 - 695,则只有 2 个组合,并且只保留这两个组合的速率
  • 问题是用BETWEEN查找不能很好的优化。
猜你喜欢
  • 1970-01-01
  • 2019-08-11
  • 1970-01-01
  • 2018-09-18
  • 1970-01-01
  • 2011-04-18
  • 2018-07-28
  • 2013-03-16
  • 1970-01-01
相关资源
最近更新 更多