我应该如何将已排序的项目存储在数据库中?

时间:2012-11-16 01:33:43

标签: ruby-on-rails database database-design activerecord relational-database

在我的应用程序中,用户可以按照他们选择的顺序重新排列他们喜爱的书籍。

我的数据库中有一个“书籍”表,每本书都有一行。目前,有一个名为“position”的整数列,用于存储每本书的位置:1为顶书,2为下册,等等。

问题在于,如果有人将书从位置#11000拖到#1位置,那么我必须对数据库进行11,000次更新。这似乎效率低下。有更好的方法吗?

我所拥有的一个想法就是让另一个名为“book_sort_orderings”的表或其他东西,每个用户都有一行。一列是一个巨大的文本列,用于存储书籍ID的排序列表。然后,当用户重新排列书籍时,我可以将此值拉出到我的代码中,在那里执行重新排列,并更新数据库行。当然,每当添加或删除一本书时,我都必须更新这个数组。这是处理事情的“正确”方式吗?或者有什么聪明的我可以做的事情来加快速度而不改变我当前的设置?

4 个答案:

答案 0 :(得分:8)

你会惊讶于一个体面的DBMS可以快速更新11,000行,假设你以“批量”方式进行(而不是为每一行单独进行数据库往返)。

但是如果你想避免这种情况,请使用旧的BASIC技巧(从BASIC仍有行号开始):留下空白!

而不是使用职位:1, 2, 3, 4, 5 etc...使用10, 20, 30, 40, 50 etc...

因此,当您需要将第一项移动(比方说)到倒数第二个位置时,只需修改10到41,然后最终得到:20, 30, 40, 41, 50 etc...。显然,如果差距被完全填满,你需要做一些摆弄,但这个策略应该能够几乎消除大量的UPDATE。


另一种可能性是实现双向链表:而不是订单,保留上一个和下一个项的ID。重新排序可以通过简单地“重新链接”ID来完成,就像在内存列表中一样。不幸的是,您还会阻止DBMS直接对项目进行排序(至少没有笨拙且可能效率低下的递归查询) - 您必须在应用程序级别进行排序,所以我建议再次进行排序


  

一列是一个巨大的文本列,用于存储书籍ID的排序列表。

请不要那样做。您违反1NF并且非常好的理由不这样做,包括数据一致性和性能(您必须重写整个字段才能对任何单个更改进行更改它的一部分)。

答案 1 :(得分:5)

您当前的解决方案似乎不适用于多个用户设置。如果在Book表中设置了图书的订单,那么它对所有用户都不是永久性的吗?

正如其他人所提到的,通常最好将数据标准化,这需要您添加另一个表,就像您所建议的那样。所以你可以有一个新的BookOrdering表。所以它有一个book_id,一个user_idposition列。这样,每个用户和每本书都有一个指定的位置。

因此会有一个默认排序(不会存储在此表中),但用户可以更改顺序。该表仅记录默认值的更改。如果要加载用户的书籍,首先要检查此表格中是否有某个user_id,然后相应地切换/调整顺序。

答案 2 :(得分:4)

使用几个SQL语句更新示例中的所有行并不是很难。您不需要在DBMS上发出11,000个更新(我认为这是您想要说的)。

首先,更新所有正在洗牌的书籍:

UPDATE book
SET position = position + 1
WHERE position < 11000
AND position >= 1

...然后设置你正在移动的书的位置:

UPDATE book
SET position = 1
WHERE id = whatever

答案 3 :(得分:0)

1。 另一个想法:

在列表中标识新的varchar列(orderCode)。此列以char格式存储每个项目的订单,如下所示:

'1','2','3','4','5','6', '7', '8', '9', '91', '92',....

现在,如果要插入1到2之间的项目,则orederCode的值将为“11”。列表顺序为:

'1','11','2','3','4','5','6', '7', '8', '9', '91', '92',....

现在我们假设您将插入11和2之间,您将插入orderCode值='12':

'1','11','12','2','3','4','5','6', '7', '8', '9', '91', '92',....

最后,如果你想从'11'和'12'插入项目,订单价值将是:'111':

'1','11','111','12','2','3','4','5','6', '7', '8', '9', '91', '92',....'99','991,...

您可以不时运行查询以将订单值修复为一个字符。

2。 更好的解决方案:

使用浮点数据类型而不是varchar。所以这个清单:

'1', '11', '111', '12', '2', '3', '4', '5', '6', '7', '8', '9', '91', '92',....

就像吼叫:

  0.1, 0.11, 0.111, 0,12, 0.3, 0.4, 0.5, 0.6, ......,0.9,0.91,....

严格来说,浮点排序比varchar排序更快。