2009-06-06 75 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 數百或數千記錄增加的所有訂單較新秩序更大的不應該是什麼像樣的數據庫的一個問題,尤其是在處理內部做的觸發會開除數據庫,(我會不是建議從你的應用程序中這樣做),但一旦你進入了數千萬,更新很多行將會很麻煩。

取決於數據的大小。