6

我有一个数据库表,它维护一些信息并且需要保持顺序。本质上,如果我列出了元素 1 到 5,并且我想添加一个新元素,那么它可以插入现有行中的任何位置,可以在最后、5 之后、1 之前的开头或中间的某处,例如 3 之后. 有没有办法使用 MySQL INSERT 语句并指定我们应该在哪一行之后插入索引?

我想不会。所以我这样做的策略是创建另一个列'order_number',它基本上记录了元素的顺序。例如,如果记录表有主键 (record_id) 和 order_number 并排列出,它看起来像这样:

 record_id     order_number

    1              1    
    2              2    
    3              3
    4              4
    5              5

要在第 3 行之后向该行添加一个新元素,结果表将如下所示:

 record_id     order_number

    1             1
    2             2
    3             3
  **6**         **4**         <------ added row 
    4           **5**         <-- changed order_number
    5           **6**         <-- changed order_number

在这种情况下,我可以通过简单地选择我想要的数据并提供 Order By order_number asc 子句来清楚地实现我想要的顺序。

但是,正如您所看到的,要进行简单的插入,它需要我更新出现在它之后的每一行的 order_number。预计该表至少有大量行(数量为 100,000),并且在每次插入操作时简单地更新每隔一行(因此锁定表)根本不可行。

在这种情况下,什么是更好的推荐策略?

4

2 回答 2

17

如果order_number不显示而仅用于排序,我建议您使用十进制数据类型而不是整数。这样,当您必须在两个现有行“之间”插入一行时,您可以设置为 order_number,即两个现有订单号的平均值。

在您的示例中:

 record_id     order_number

    1             1.0
    2             2.0
    3             3.0
  **6**           3.5          <---- added row 
    4             4.0           <-- no change
    5             5.0           <-- no change

但是有一个问题,如果您在同一区域中继续插入数字,则某些订单号可能会导致您选择的数据类型的精度太接近,以至于无法相互区分。

为避免这种情况,您的插入过程将必须检查两个现有订单号是否太接近。在这种情况下,它可以重新分配其他附近行的一些订单号,“拉伸”上方和下方的订单号,为新值“腾出空间”。

您还可以有一个定期运行的“清理”过程,并在整个或大部分表格中执行此“拉伸”。

于 2012-12-02T23:52:46.550 回答
5

我找到了类似问题的答案:https ://stackoverflow.com/a/6333717/1010050

总而言之,它会增加您将要添加的记录 ID 以下的所有记录 ID,以保持一致性。这仍然需要您更新所有记录 ID,因此它不是最有效的。与您的方法相比,它确实具有维护数据库中的物理订单的好处,而不仅仅是像您那样的虚拟订单。

我能想到的另一种方法是记录每条记录的子记录 ID 和父记录 ID,而不是订单号,类似于双向链接列表。然后在中间插入一个元素只需要更新另外两条记录,而不管表的大小。这与物理排序错误的解决方案具有相同的缺点,因此以有序方式从表中读取会更昂贵。

例如:

record_id        parent_id      child_id
   0                 NULL          1
   1                 0             2
   2                 1             NULL

当我们在 之后插入一条记录record_id = 1时,表格变为:

record_id        parent_id      child_id
   0                 NULL          1
   1                 0             3
   2                 3             NULL
   3                 1             2

请注意只有 ID 1 和 2 的parent_idchild_id必须更改。

我认为在这两种解决方案之间,要考虑的最重要的事情是您最常见的操作是什么:按顺序读出值,或者在中间某处写入一个新值。如果它正在读取,那么更新记录 ID 将是您维护数据库物理顺序的最佳选择。如果编写,那么您可以使用我建议的类似于双向链表的方法或您自己的排序方法来优化它。

问题更新后总结: 看到更新大部分记录是不可行的,那么我找到的另一个答案肯定是无效的。然而,将其视为类似于双向链表的解决方案仍然是合理的。

于 2012-12-02T23:57:17.327 回答