我有一个数据库表来维护一些信息,并且需要保留订单。基本上如果我列出了元素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子句来清楚地实现我想要的顺序。
但是,正如您所看到的,要做一个简单的Insert,它需要我更新每一行的order_number 它出现在它之后。该表预计至少具有大量的行(大小为100,000),并且在每次单个插入操作时简单地更新每隔一行(因此锁定表)根本不可行。
在这种情况下,推荐的策略是什么?
答案 0 :(得分:14)
如果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
但是有一个问题,如果你继续在同一个区域插入数字,一些订单号可能会导致你所选择的数据类型的精度太接近,足够接近而不能彼此区分。< / p>
为避免这种情况,您的插入程序必须检查两个现有订单号是否过于接近。在这种情况下,它可以重新分配其他附近行的一些订单号,“拉伸”上方和下方的订单号以“创建空间”以获得新值。
您还可以定期运行“清理”程序,并在表格的整个或大部分内“拉伸”。
答案 1 :(得分:4)
我找到了类似问题的答案:https://stackoverflow.com/a/6333717/1010050
总之,它会将所有记录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_id
和child_id
只能更改。
我认为在这两种解决方案之间,最重要的考虑因素是你的最常见的操作:按顺序读出值,或者在中间某处写一个新值。如果正在读取,那么更新记录ID将是维护数据库物理顺序的最佳选择。如果是写作,那么你可以使用我建议的类似于双向链表的方法或你自己的订购方法来优化它。
问题更新后的摘要: 看到更新大多数记录是不可行的,那么我发现的另一个答案绝对无效。然而,处理它的解决方案类似于双重链表仍然是合理的。