假设我有1000多个或更多记录,我能想到改变记录顺序的唯一方法就是更新所有记录位置。
假设我有一个名为position
的列,其中包含:
id name position
1 apples 1
2 oranges 2
3 pears 3
4 bananas 4
5 candy 5
假设用户想要在candy
和oranges
之间移动pears
。为此,我需要将candy
的位置更新为3
,然后使用position
增加3-4
条记录1
。虽然可以使用单个查询完成,但仍需要锁定所有正在更新的记录,因此不是最佳记录。
还有另一种方法可以做到这一点,因为当你有很多记录时这似乎效率低下。我需要一种有效的方法来改变几个记录的位置,这些记录涉及尽可能少的表修改。
答案 0 :(得分:1)
我从ext
文件系统如何解决碎片问题中窃取了一个主意:
随机初始化您的位置字段,占用您数据类型所有可能值的范围。
每次您需要更改某些内容的位置时,只需在希望记录移动的范围内寻找一个空值,然后随机选择一个即可。
示例:
| id | pos |
| 1 | 1002 |
| 2 | 15000 |
| 3 | 192185 |
现在,如果您想将3
移到2
之前和之后1
,则只需选择一个随机位置pos
,例如1002 < pos < 15000
,这样您就可以将得到:
| id | pos |
| 1 | 1002 |
| 3 | 9421 |
| 2 | 15000 |
从统计上讲,这将很好地起作用,直到大约80%
个空间已满为止。有时您可能会得到零长度范围,在这种情况下,您将需要更改其他记录之一的位置,以便为新记录腾出空间。示例:
| id | pos |
| 1 | 1002 |
| 2 | 1003 |
| 3 | 15000 |
同样,如果所需的新订单为1 > 3 > 2
,则您首先需要为1
找到一个新的地点,然后在它们之间放置3
。假设是新的rand(0, 1002) == 42
,那么您将得到类似的内容:
| id | pos |
| 1 | 42 |
| 3 | 510 |
| 2 | 1003 |
在实现此算法时,请注意,进行空间操作可以递归进行,但是正如我所说,除非您有很多记录并且您的空间已达到80%以上,否则这是不太可能的。
答案 1 :(得分:0)
不是使用额外的字段来对数据进行排序,而是引入NextItem
外键。您可以保留项目的原始主键。主键仍将作为标识值,但与排序顺序无关。
你可以拥有:
ID: 33, Name: The first item, NextItem: 48
ID: 48, Name: The second item, NextItem: 12
ID: 12, Name: The last item, NextItem: NULL
现在,您只需更改单个记录的'NextItem'即可完成重新排序数据。
答案 2 :(得分:-1)
合适的解决方案取决于您如何使用位置信息以及您的速度要求。如果您希望数据库在检索记录时执行位置排序(使用“ORDER BY位置”),我想不出一种方法可以避免更新受影响的每一行的位置信息。您可以通过将位置信息保存在单独的表中来略微减少过度杀伤,该表的行仅包含常规表PK的外键以及列“位置”。这样,您的数据库只需要在更小的表上进行更新。