Ruby on rails 如何在数据库中存储已排序的项?

Ruby on rails 如何在数据库中存储已排序的项?,ruby-on-rails,database,database-design,activerecord,relational-database,Ruby On Rails,Database,Database Design,Activerecord,Relational Database,在我的应用程序中,用户可以按照他们选择的任何顺序重新排列他们喜爱的书籍 我的数据库中有一个“books”表,每本书有一行。目前,有一个名为“position”的整数列存储每本书的位置:1表示最上面的书,2表示下一本书,以此类推 问题是,如果有人把一本书从(比如)11000号位置拖到(比如)1号位置,我就必须对数据库进行11000次更新。这似乎效率低下。有更好的方法吗 我的一个想法是创建另一个名为“book\u sort\u orderings”的表,每个用户都有一行。其中一列将是一个巨大的文本列

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

我的数据库中有一个“books”表,每本书有一行。目前,有一个名为“position”的整数列存储每本书的位置:1表示最上面的书,2表示下一本书,以此类推

问题是,如果有人把一本书从(比如)11000号位置拖到(比如)1号位置,我就必须对数据库进行11000次更新。这似乎效率低下。有更好的方法吗


我的一个想法是创建另一个名为“book\u sort\u orderings”的表,每个用户都有一行。其中一列将是一个巨大的文本列,用于存储图书ID的排序列表。然后,当用户重新排列书籍时,我可以将该值提取到代码中,在那里执行重新排列,并更新数据库行。当然,无论何时添加或删除书籍,我都必须更新此数组。这是处理事情的“正确”方式吗?或者,在不更改当前设置的情况下,我可以做些聪明的事情来加快速度吗?

您当前的解决方案似乎不适用于多个用户设置。如果在
book
表中设置了书籍的顺序,那么它对所有用户来说不是永久的吗

正如其他人所提到的,通常最好保持数据规范化,这需要您按照建议添加另一个表。因此,您可以有一个新的
图书订购表。所以它会有一个
图书id
,一个
用户id
位置
列。这样,每个用户和每本书都有一个指定的位置


因此会有一个默认顺序(不会存储在此表中),但用户可以更改顺序。该表将只记录默认值的更改。当您要加载用户的书籍时,首先要检查此表中的某个用户id,然后相应地移动/调整顺序

用几个SQL语句更新示例中的所有行并不困难。您不需要在您的DBMS上启动11000个更新(我想这就是您想要说的)

首先,将所有正在洗牌的书籍更新到一个位置:

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

假设您以“批量”方式更新11000行(而不是为每一行进行单独的数据库往返),那么一个好的DBMS更新11000行的速度会让您感到惊讶

但是,如果您想避免这种情况,请使用旧的基本技巧(从基本仍然有行号的时候开始):留下空白

不要使用位置:
1、2、3、4、5等。
使用
10、20、30、40、50等。

因此,当您需要将第一个项目移动到倒数第二个位置时,只需将10修改为41,您将得到:
20、30、40、41、50等等。
。显然,你需要做一些修改以防缺口被完全填补,但这种策略应该能够几乎消除大规模的更新


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


其中一列将是一个巨大的文本列,用于存储图书ID的排序列表

请不要那样做。您将违反,并且有很好的理由不这样做,包括数据一致性和性能(您必须重写整个字段,以便对其任何部分进行任何更改)。

1另一个想法: 在列表中标识新的varchar列(orderCode)。此列以字符格式存储每个项目的订单,如下所示:

'1','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,....
现在,如果要插入介于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',....
就像贝娄说的:

'1','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排序快。

您是说在您描述的示例中,您要向数据库发送11000条SQL更新语句吗?因为有更有效的方法更新一个表的多行。嗯,这个“解决方案”正在变得越来越糟糕-保持数据规范化!无论如何,我会1)每个用户都有一个层次结构,2)查看一个“层次结构”数据类型(比如SQL Server中使用的数据类型,在其他引擎中必须手动),该数据类型允许层次结构(此处排序)几乎无限期地维护;它基于“拆分”节点工作,就像浮点数总是有一个比它“稍大”和“稍小”的数字一样。