4

我有一个表格,其中包含有关“交易”的数据。交易要么已关闭,要么已打开,并在“is_closed”列中标记。(这是,或当然,索引)。

大约有 10,000 个“打开”行和 10,000,000 个“关闭”行。每个“打开”行大约每秒更新一次。(此处仅更新未索引的字段)。一旦一行被“关闭”,它将永远不会再被更新。(只读)。

我永远不需要运行处理打开和关闭行的选择,所以问题是;我应该将表分成两个表(打开和关闭),结构相同吗?

单个表的缺点是每秒钟我都会对 10,000,000 行表运行更新。两个表的缺点是存在一种代码重复,当关闭“交易”时,我需要将它们从一个表中删除,然后添加到另一个表中。

4

5 回答 5

1

把它们分成两张桌子。我认为没有缺点:

  • 两个表的缺点,就是有一种代码重复

所以呢?您的目标是性能,而不是更少的代码行数。

  • 并且在关闭“交易”时,我需要将它们从一张桌子上删除,然后添加到另一张桌子上。

多几行代码。一些 UPDATE 程序将被转换为 INSERT/DELETE 程序。


优点是:

  • 您在两个表中都少了一个索引。
  • 任何复合索引(包括open/closed标志)都会有点窄。
  • 更重要的是,您在表中具有高流量的所有索引都会小得多。
于 2012-06-27T16:59:56.070 回答
1

如果收盘与开盘的比率 >= 1000(如您所述),那么制作两个不同的表会更好。

您可以通过使用多态性来避免代码重复。您可以通过名称AbstractDeal创建一个抽象交易基类,然后扩展两个具体类OpenDealCloseDeal。您可以将这两个具体类分别映射到您的表中。

我希望这将是一个更好的解决方案。

于 2012-06-27T14:49:24.693 回答
1

在某些情况下,像您这样的布尔值(true 和 false,或 1 和 0)列是可以的,但是如果您发现自己为这样的列建立索引,那么您可能已经越界了。

如果这些值是均匀分布的(50% 正确,50% 错误),MySQL 甚至不会使用索引,除非它是一个覆盖索引。通过二级索引查找每一行的成本很高,其中大部分数据集将被返回,因此 MySQL 将改为执行简单的表扫描。

在您的情况下,由于您正在查询较小的分布(1% 错误),因此 MySQL 可能实际上会使用该索引。

但是,您必须想知道为什么必须在索引中存储这么多甚至没有被使用的真实值,然而,它们会减慢索引更新,并且只是浪费空间。

...修改...

相反,请考虑以另一个表的形式将索引存储在外部。考虑添加一个名为 open_deals 的表,其结构如下,其中 deal_id 是交易和 open_deals 的主键:

deal_id
----------
100
121
135

要获得您的公开交易,只需执行以下操作:

SELECT deals.*
FROM open_deals
STRAIGHT_JOIN deals
  ON deals.deal_id = open_deals.deal_id

我们使用直接连接,因为我们总是知道我们将从左到右连接,并且我们正在使 MySQL 不必考虑它。

由于 open_deals 仅包含单个索引列,因此该索引将充当覆盖索引。在正确配置的强大服务器上,索引将存储在内存中,因此表会非常快。

在内部,连接类似于使用原始二级索引,但没有所有这些未使用值的开销。

为了获得最佳性能,请确保将新值附加到 open_deals 表的末尾,或者换句话说,所有新值都应该大于上一个值,但无论如何您都在这样做。

要将交易设置为打开,将其附加到 open_deals 表,并将其标记为已关闭,从 open_deals 表中删除 id。

这里的优点是您不必在表之间移动记录,不必更新其他索引(使用 InnoDB 的聚集索引更糟)。此处更新的唯一索引是 open_deals 表上相当小的索引。

于 2012-06-27T15:54:01.497 回答
1

我认为您可以按状态列对表进行分区,因此您在逻辑上将拥有 1 个表。列表分区似乎适合您的情况。然后,如果需要,您可以进一步细分“封闭”分区......

于 2012-06-27T14:42:43.953 回答
0

只要两个表都在同一个表空间中,您几乎不会从拆分或分区表中获得任何收益——代码简单的好处非常有利于将其保持在一个表空间中。

InnoDB 将进行行级锁定,因此您最终不会因已关闭的交易阻塞未完成的交易而告终。

于 2012-06-27T14:48:09.270 回答