在数据库中的一组记录上存储排序顺序的最有效方法是什么?

时间:2011-07-24 00:20:11

标签: mysql algorithm database-design performance

假设PHP / MYSQL,但我不一定需要实际代码,我只对其背后的理论感兴趣。

一个很好的用例是Facebook的照片库页面。您可以在页面上拖放照片,这会触发Ajax事件以保存新的排序顺序。我正在实现非常相似的东西。

例如,我有一个数据库表“照片”,大约有一百万条记录:

照片 id:int, userid:int, albumid:int, sortorder:int, filename:varchar, title:varchar

假设我有一张包含100张照片的相册。我将照片拖放到一个新位置,然后激活Ajax事件以保存在服务器上。

我应该将整个照片ID数组传递回服务器并更新每条记录吗?假设输入验证为“WHERE userid = loggedin_id”,因此恶意用户只能处理自己照片的排序顺序

我是否应该传递照片ID,其先前的排序顺序索引及其新的排序顺序索引,检索这两个索引之间的所有记录,对它们进行排序,然后更新它们的订单?

如果单个图库中有数千张照片并且排序顺序发生了变化,会发生什么?

5 个答案:

答案 0 :(得分:18)

使用定义订单的integer列怎么样?默认情况下,您指定数字* 1000,如1000,2000,3000 ....如果您在1000和2000之间移动3000,则将其更改为1500.因此,在大多数情况下,您根本不需要更新其他数字。我使用这种方法,效果很好。您也可以使用double,但是您无法控制精度和舍入误差,所以请不要使用它。

所以算法看起来像是:假设你把B移到A之后的位置。首先执行选择以查看A旁边的记录顺序。如果它至少高于+2 A的顺序然后你只需设置B的顺序以适应它们之间。但如果它只是+1高(A之后没有空格),你选择B的边界记录来看这边有多少空间,除以2然后将这个值加到A之间所有记录的顺序上。和B.就是这样!

(请注意,对于包含多个查询的任何算法,您应该使用事务/锁定,因此这也适用于这种情况。最简单的方法是使用InnoDB事务。)

答案 1 :(得分:5)

存储为链接列表,sortorder是对集合中下一个photo_id的外键引用。

答案 2 :(得分:1)

这可能是一个'链表'结构。

答案 3 :(得分:0)

对我来说,第二种更新方法是去的方法(仅更新更改的范围)。你提到“如果在一个画廊中有成千上万的照片会发生什么......”,对我来说这是永远不会发生的。让我们以你的facebook为例。 Facebook不会在一个页面上显示数千张照片,而是将其分成每页约10-20张。

答案 4 :(得分:0)

我在非关系数据库中执行此操作的方法是按照所需顺序在“相册”实体/记录上存储照片ID列表。重新排序照片会导致重新排序列表,并且只会写入一个数据库。

某些SQL数据库(例如,PostgreSQL)具有本机列表数据类型,但MySQL没有。您可以在MySQL上将列表序列化为字符串或二进制文件。

第3版正常形式的数据库专家会尖叫你,这是一种糟糕的方法,但RDBMSs针对OLAP类型查询进行了优化,其中查询灵活性比读取性能更重要。 Webapps最好用“写重,读取光”策略编写,这种非规范化与此完全一致。