簡體   English   中英

在數據庫中實現分層數據結構

[英]Implementing a hierarchical data structure in a database

我知道有兩種方法:鄰接列表和嵌套樹。 據說由於大量查詢,鄰接列表在遍歷上使用會很慢。 但我不知道這方面的任何實際數字。 我正在制作的網站將有200頁。 遍歷生成(例如)站點地圖需要花費超過0.3秒的時間嗎?

使用LAMP堆棧在MySQL(innoDB)上運行。

如果可能的話,我更願意實現鄰接,因為設計更簡單。

謝謝。

除了你提到的兩個選項之外,還有更多的選擇。 有:

  • 鄰接列表(幾乎每個人都使用的“parent_id”)
  • 嵌套集
  • 路徑枚舉
  • 關閉表(又稱鄰接關系)

請參閱我的回答“ 什么是將平台解析成樹的最有效/優雅的方法?

或者幾本書:

MySQL中管理分層數據的文章詳細介紹了這一點。

我建議使用“嵌套集”技術,因為它允許您在一個查詢中獲取整個樹(及其子節點)。 基本上讀取是便宜的,但寫入是昂貴的,因為整個樹必須重新平衡。 但是如果你有99%的讀數,那么它是完全合理的。

解析鄰接列表的天真方法需要大量查詢,而對於大型列表,可能需要花費大量時間來構建內存。 作為參考,我所指的天真方法可以概括為:選擇沒有父項的所有項目,然后為每個項目遞歸地獲取它的子項。 此方法需要n + 1個數據庫查詢。

我使用以下方法構建一個帶有1個查詢的鄰接列表。 從數據庫中選擇所有項目。 將所有項目轉移到由其鍵索引的數組中。 遍歷數組並將父對象的引用分配給每個子對象。 第二次遍歷數組並刪除僅留下根級對象的所有子對象。

既然你提到了LAMP堆棧,那么PHP代碼大致如下:

<?php
// Assumes $src is the array if items from the database.
$tmp = array();

// Traverse the array and index it by id, ensuing each item has an empty array of children.
foreach ($src as $item) {
  $item['children'] = array();
  $tmp[$item['id']] = $item;
}

// Now traverse the array a second time and link children to their parents.
foreach ($tmp as $id => $item) {
  if ($item['parent_id'] != 0 || $item['parent_id'] !== NULL) {
    $tmp[$item['parent_id']]['children'][$id] = &$tmp[$id];
  }
}

// Finally create an array with just root level items.
$tree = array();
foreach ($tmp as $id => $item) {
  if ($item['parent_id'] == 0 || $item['parent_id'] === NULL) {
    $tree[$id] = $item;
  }
}

// $tree now contains our adjacency list in tree form.
?>

請注意,此代碼旨在說明從單個數據庫查詢構建鄰接列表的技術。 它可能可以針對更少的內存消耗等進行優化。它還沒有經過測試。

吉姆

以下是一些可能對您有所幫助的問題:

SQL如何存儲和導航層次結構

哪個是我導航的最佳數據庫架構

我認為另一種方法稱為“嵌套集”,而不是“嵌套樹”。

無論如何,站點地圖的一個好處是你可能知道它的最大深度。 我認為鄰接模型的問題是相應的SQL一次只能在一個層面上工作,所以如果你有'n'個級別,那么你需要一個'n'個SQL語句的循環...但我認為(我'我不確定)如果您事先知道最大'n',那么您可以編寫相應的固定數量級別的SQL。

0.3秒聽起來像很長一段時間才能看到200頁,所以這可能還行。

站點地圖也不經常更新; 因此,即使從SQL檢索確實需要很長時間,您也可以將檢索/計算的樹緩存在RAM中。

或者,不要擔心構建樹的SQL,您可以盡可能簡單地存儲它(作為鄰接列表),從數據庫中將其作為一組簡單的行檢索,並在RAM中構建樹(使用循環)您的高級編程語言)而不是使用SQL中的循環來使用SQL語句構建樹。

為了完整性:Oracle具有START_WITHCONNECT_BY運算符:請參閱此分層查詢文檔。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM