2009-06-06 97 views
0

嗯,这听起来像一个蹩脚的问题,我知道。这可能是最明显的事情之一,但我一直在想出一个排序数据库中的条目的好方法。表条目订单

图像表看起来像这样:

entry_id | entry_data 
------------------------- 
1   | data1 
2   | data2 
...  | ... 
n   | datan 

entry_id当然是主键与AI选项,让所有条目都有一个唯一的ID。 现在。我想订购这些数据。说我希望entry_id = 2首先不改变它的entry_id。然后该表需要另一列来存储订单号。 我试过2种方法。

  1. entry_order_no:这将基本保持物品的订单号。任何新项目将始终添加到最后。

  2. left_id + right_id:这个方法被phpBB使用。不知道为什么它需要right_id?

我似乎更喜欢第一种方法,但如何在以后对数据进行排序。 让我们假设我想从最后一个位置新添加项目移动到第二个位置。 我一直在做的方式我正在使用索引表,其中索引是订单号。每个索引都包含具有entry_id的关联数组。这样,我“简单地”做了foreach循环与第二名下的所有条目的更新。这可能会工作几行。甚至可能是数十。但是当你有几百个时呢?这似乎非常低效。第二个看起来好一点。但有些东西仍然告诉我有更好的方法。

请确认。

回答

2

我不知道为什么你要做到这一点的真实性质,所以它是一种很难说,但至于你的低效foreach循环,停止使用套迭代方法 - 使用集合操作,他们的速度更快,而且数据库的意义。所以不是...

for row in db>2 
    entryorderno += 1 

做到这一点...

UPDATE Table 
SET entryorderno = entryorderno + 1 
WHERE entryorderno > 2 

此外,从亚历克斯马尔泰利说,这样做应该是一段时间很OK拉,但最终你必须使用新的间距重新设置所有内容......但是该字段上的聚集索引将通过该ID保持顺序......当然这也意味着如果表是大型表,则插入到表的中间可能是资源密集型的。

+0

那么你的建议现在看起来如此明显。我知道必须有一些简单的解决方案。 – 2009-06-06 14:56:56

0

当我们在primeval Basic中编程时,我们编号了行“10,20,30 ......”,所以如果我们需要在现有的行之间插入一行,我们可以给它编号,例如25,而不用重新编号其他。如果您的唯一目的是保持行的顺序,并让您用最少的大惊小怪改变顺序,而不重新编号(mysql在内部将不得不更新索引),那么您可以对您的“输入顺序”使用类似的技巧。该列,但这比自己做的更快,更有可能不会 - 在你的设置上尝试一些基准来确认这一点)。使用BIGINT大的初始增量,例如1024,并且在需要重新构建该列之前,您应该对很多重排序都适用。

0

一个有趣的问题。 left_id/right_id可能是存储分层(而不是顺序)数据的嵌套集方法的实现。请参阅Trees in SQL

对于这个问题,我采取了两种方法。一个是你正在描述的蛮力,当你添加/改变/删除一个条目时,你可以根据需要调整所有的数字。另一种是只维持一个等级,所以当一个入门级别升高时,你只需增加它的等级号码而不修改任何其他入口的等级。例如,每次用户点击向上箭头时,条目的等级就会被添加到它,并且您按照等级重新呈现列表,在这种情况下,节点向上移动列表中的一个等级。

一旦您获得大量数据,这两种方法都不是理想的,但通常在这一点上,您不再手动维护排序顺序,并且设计了一种自动排序的算法。

+0

当我看到这个问题时,我也是Celko。 IIRC从阅读他关于树和层次结构的书中读到他喜欢使用广义空间值,以便在这两者之间插入一个新的价值,就像Alex Martelli在这个主题中所描述的那样。 – onedaywhen 2009-06-08 10:16:48

1

phpBB正在使用更智能的方法:left_id和right_id对应于树的节点,作为嵌套集的一部分。如果性能将会成为问题,这可能是您想要采用的路线(因为您似乎担心这一点)。这里有一个very thorough implementation walkthrough of nested sets

但是请注意,数据库通常意味着无序的数据。要获取排序数据,您通常会检索您感兴趣的所有行,然后执行后处理 - 例如,使用ORDER BY子句或在结果返回后对结果进行排序。这就是说,如果需要将排序作为数据本身的一部分进行存储(例如,因为无法计算或基于用户首选项),通常使用另一个包含排序的表来完成此操作或者如上所述通过嵌套集方法中的附加列。

0

如果您需要人工排序(你不能排序上的一些列dynamicaly创建一个排序),您必须添加一个Position列。当你重新排序两行时,如果使用密集编码,则必须更改它们之间的所有行。

你必须使用一赔编码选项 - 例如第一行获得位置100,第二个200,第三个300,等等。这会增加逻辑的复杂度,但允许您执行大量重新排序操作,而无需修改多行。

0

如何存储一个简单的排序顺序列,并使用触发器和存储类函数在你的数据库?

,只要你更新order列和1 数百或数千记录增加的所有订单较新秩序更大的不应该是什么像样的数据库的一个问题,尤其是在处理内部做的触发会开除数据库,(我会不是建议从你的应用程序中这样做),但一旦你进入了数千万,更新很多行将会很麻烦。

取决于数据的大小。