假设我有两个表surveys
和surveyQuestions
surveys
有一个主索引surveyUniqueId
surveyQuestions
有一个主索引questionUniqueId
,并且有另一个列surveyUniqueId
映射到survey
用户创建一个新的survey
,然后添加surveyQuestions
。每次添加surveyQuestion时,ajax调用都会在surveyQuestions
表中创建新行。
现在,问题来了,用户可以重新安排调查问卷中问题的顺序。
存储每次调查问题顺序的最佳方式是什么?
我想到了两个选项:
-
选项1:在
surveys
表上创建questionOrder
列,用于存储questionUniqueId
s的排序数组。基本上,每次用户添加、删除或移动问题时,发送标准ajax消息以保存问题,然后遍历UI中的所有问题,创建questionUniqueId
的有序列表,并发送第二个ajax请求以更新survey
的questionOrder
列。稍后,在构建UI时,我可以使用该列表以相同的顺序呈现问题 -
选项2:在
surveyQuestions
表上创建questionIndex
列,存储每个问题的索引。基本上,当用户添加新问题时,只需将该问题保存为添加了相应索引的问题,然后,每次用户删除或移动问题时,循环遍历UI中创建和更新问题数组中的所有问题,并在服务器上使用该更新数组中的问题索引,因为它是questionIndex
一些笔记:
- 对于我来说,选项2似乎过度,因为它需要再次保存每个问题行,当只有索引改变时。
-
surveyQuestions
只能属于一个survey
-
survey
永远不会有超过100个问题 - 用户可以在任何索引中添加问题、删除问题和重新排列问题。UI使用jQuery UI的sortable()
- 如果有关系,我在服务器端使用PHP
如何存储问题顺序?这其中之一,还是其他我没想到的方法?
关于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约束来确保每个组中只有1行是尾(NULL),并使用复合键来防止一个组中的一行引用另一个组的行。
如果您的应用程序代码只知道"insert at index"值,而不知道要插入的行的主键,您还需要一个CTE来递归地迭代Next
值以找到要插入的位置。
如果您曾经考虑过在数据库的字段中存储一个"数组",那么请仔细考虑一下这是否是个好主意。
当然,对于100个问题,在最坏的重新排序场景中,您可能需要更新100行。但这是100个int(技术上甚至可以是smallint)。如果你正在更新可变长度字符串值,你可能会考虑使用它;但是,与维护(和构造)这样一个"数组"字段同时保持引用完整性的工作量相比,更新100个整数值的成本应该是微不足道的。
…然后你必须考虑数据库所擅长的特征的牺牲;而不是SELECT [fields] FROM [child] WHERE [parent]_id = X ORDER BY [sequence field]
,你必须拉X的数组,解析它,拉子值,然后按解析序列排序。如果您想更改该序列,则必须重新打包子标识符(这意味着您必须插入子数据以在"客户端"代码甚至可以对其进行排序之前获得标识符)
(改写)
每个问题应该有一个唯一的id。这个id与屏幕上的排序无关。
顺序是一个id列表。这个列表(我假设)是由UI维护、洗牌、添加、删除等,对吗?这个列表除了决定以什么顺序显示哪些问题之外,没有任何用处。
因此,UI获取、修改和存储问题id的逗号。该列表的内容和顺序控制显示。它可能是一个TEXT
字段,因为它对MySQL没有用处,只对UI有用。大多数应用语言都可以轻易地将列表内爆。
当我们说优化的话时,我们应该清楚地了解我们真正应该优化的是什么。
1)如果你创建一些管理面板与调查的公共网站选项1是唯一正确的选择。与源代码的简单性和订单字段的优势相比,您在编辑调查问卷时所做的100 * x更新的开销是微不足道的。
2)如果你为成千上万的用户创建一些界面,这些用户将创建数百万个带有数十亿个问题的调查-好吧,优化是需要的,但订单字段仍然太好了,无法拒绝它。所以@Dai解在这种情况下是有用的。