我应该如何在MySQL后端存储可排序元素的顺序

时间:2016-10-28 22:11:50

标签: php mysql

考虑我有两个表surveyssurveyQuestions

surveys有一个主要索引surveyUniqueId

surveyQuestions有一个主要索引questionUniqueId,还有另一列surveyUniqueId,可将其映射到survey

用户创建新的survey,然后向其添加surveyQuestions。每次添加surveyQuestion时,ajax调用都会在surveyQuestions表中创建新行。

现在,这就是问题,用户可以重新排列调查问题的顺序。

为每项调查存储问题顺序的最佳方法是什么?

对我来说,有两种选择:

  • 选项1:questionOrder表格上创建surveys列,以存储questionUniqueId的已排序数组。基本上,每次用户添加,删除或移动问题时,都会发送标准的ajax消息来保存问题,然后循环遍历UI中的所有问题,创建questionUniqueId的有序列表并发送第二个ajax请求更新questionOrder的{​​{1}}列。稍后,在构建UI时,我可以使用该列表以相同的顺序呈现问题

  • 选项2:survey表格上创建questionIndex列,以存储每个问题的索引。基本上,当用户添加新问题时,只需保存添加了适当索引的一个问题,然后,每次用户删除或移动问题时,循环UI创建和问题更新数组中的所有问题,并在服务器上,使用该更新数组中的问题索引,因为它是surveyQuestions

有些说明:

  • 对我来说,选项2似乎过多了,因为只需要更改索引时需要再次保存每个问题行。
  • questionIndex只能属于一个surveyQuestions
  • survey永远不会有超过100个问题
  • 用户可以在任何索引处添加问题,删除问题和/或重新排列问题。 UI使用jQuery UI的sortable()
  • 如果重要,我在服务器端使用PHP

您将如何处理存储问题订单?其中一种,或其他一些我没想过的方式?

4 个答案:

答案 0 :(得分:2)

关于在RDBMS表中存储/表示有序项的子问题:

另一种方法是用“下一个列表”来表示顺序,即“指定的元素在此之后” - 即一个链表:

所以最初你可能有这些数据:

Id    Name       SortOrder
--------------------------
101   Foo        3
102   Bar        1
103   Baz        2

可以存储为:

Id    Name       Next
--------------------------
101   Foo        (NULL)
102   Bar        102
103   Baz        101

您需要某种方式来存储HEAD项目,或者遍历项目以查看哪些项目没有父项。

这种方法的优点是重新排序少量行或在给定位置插入行很便宜:您只需要更新两行而不是整个范围。缺点是您需要注意参照完整性以避免丢失Next行,以及重复(表示图形周期)或值NULL值不正确的行。幸运的是,这些可以使用自我外键和非NULL过滤的UNIQUE约束来强制执行,但是如果您在一个表中存储多个组,则还需要一个自定义CHECK约束来确保每个组中只有一行是尾(NULL),并使用复合键来防止一个组中的行引用另一个组的行。

如果您的应用程序代码只知道“insert at index”值而不是行的主键,那么您还需要CTE递归遍历Next值以找到要插入的位置插入后。

答案 1 :(得分:1)

如果您曾想过在数据库的字段中存储“数组”,那真的非常怀疑它是不是一个好主意。

当然,有100个问题,您可能需要在最坏情况重新订购方案中更新100行。但那是100个INT(技术上甚至可能是SMALLINT)。如果要更新可变长度字符串值,可能会考虑这个问题;但是,与维护(和构造)这样的“阵列”字段同时保持参照完整性的努力相比,更新100个整数值的成本应该是微不足道的。

...然后你必须考虑数据库的功能牺牲;而不是SELECT [fields] FROM [child] WHERE [parent]_id = X ORDER BY [sequence field]你需要拉X的数组,解析它,拉出子值,然后按解析的序列对它们进行排序。如果要更改该序列,则必须重新打包子标识符(这意味着您必须插入子数据才能获得标识符,然后“客户端”代码甚至可以对其进行排序。)

答案 2 :(得分:1)

(重写)

每个问题都应该有唯一的ID。此ID与屏幕上的排序无关。

订单是ID列表。这个列表(我假设)由UI维护,改组,添加,删除等,对吗?除了决定以什么顺序显示哪些问题之外,列表没有用处。

因此,UI获取,修改并存储一个问题ID的commalist。此列表的内容和顺序控制显示。它可能是TEXT字段,因为它对MySQL没有用处,只能用于UI。大多数应用程序语言都可以轻易地破坏/爆炸列表。

答案 3 :(得分:0)

当我们用优化的话说话时,我们应该清楚地了解我们应该优化什么。

1)如果您使用调查为公共站点创建一些管理面板,则选项1是唯一正确的选择。编辑调查时所做的100 * x更新的开销与源代码的简单性和订单字段的优势相比没什么可比性。

2)如果你为用户的thoudsands创建了一些界面,这将创建数百万个带有数十亿个问题的调查 - 好的,需要进行优化,但订单字段仍然太好,不能拒绝它。所以@Dai解决方案在这种情况下可能很有用。