2013-04-15 84 views
0

我用修改前序樹存儲在我的一個表LOC_TABLE應用GEO位置。例如子樹的例子希臘看起來是這樣的:修改序樹:選擇特定類型的頂級元素

+-------+---------------+-----+-----+------+ 
| ID | NAME   | LFT | RGT | TYPE | 
+-------+---------------+-----+-----+------+ 
| 10 | Greece  | 100 | 200 | 3 | 
| 20 | Crete Isl. | 120 | 140 | 4 | 
| 25 | Crete-Vamos | 121 | 122 | 4 | 
| 26 | Crete-Rethymno| 123 | 124 | 4 | 
.... 
+-------+---------------+-----+-----+------+ 

TYPE列用於存儲類型定位(3 - 國家,4 - 市)。正如您所看到的,克里特島被存儲爲城市,其中包含其他城市(例如,VamosRethymno)作爲其子。

我需要進行兩種類型的查詢:

1)獲取在特定父特定類型的所有位置。

2)獲取在特定父特定類型的所有頂部位置:對於僅Crete Isl.應查詢內部希臘城市時,返回地點提供的例子,因爲Crete Isl.沒有型城市的父母,而城市VamosRethymno有型城市的母公司 - Crete Isl.

什麼在每種情況下進行快速查詢?對於第一種情況,我考慮使用兩個查詢(首先,獲得希臘的LFT和RGT,第二個獲取類型= 4的所有位置,其具有適當的LFT和RGT)或使用某種連接來獲得所有一步到位。哪種方法最好?

對於第二種情況,我沒有任何當前合適的想法。我嘗試了簡單的子選擇:

select loc.* from LOC_TABLE loc 
where 4 not in 
(select TYPE from LOC_TABLE p 
    where p.lft < loc.lft AND p.rgt > loc.rgt) 
AND loc.LFT > 100 AND loc.RGT < 200; 

但它太長了。

我不介意增加更多的專欄,並與一些值,這將有助於加快這兩種類型的查詢填充它們。但我需要快速獲取數據。

謝謝。

回答

1

對於那些與:id給出的ID特定記錄的城市和後代的所有記錄,使用

SELECT descendant.ID, descendant.NAME, descendant.TYPE 
FROM LOC_TABLE location 
INNER JOIN LOC_TABLE descendant 
    ON descendant.LFT > location.LFT AND descendant.RGT < location.RGT 
WHERE location.ID = :id AND TYPE = 4 

對於那些與ID記錄的城市和子由:id,使用givien所有記錄

SELECT child.ID, child.NAME, child.TYPE 
FROM LOC_TABLE location 
INNER JOIN LOC_TABLE child 
    ON child.LFT > location.LFT AND child.RGT < location.RGT 
LEFT OUTER JOIN LOC_TABLE intermediate 
    ON intermediate.LFT < child.LFT 
    AND intermediate.RGT > child.RGT 
    AND intermediate.LFT > location.LFT 
    AND intermediate.RGT < location.RGT 
WHERE location.ID = :id 
AND child.TYPE = 4 
AND intermediate.ID IS NULL 

與條件intermediate.ID IS NULL沿LEFT OUTER JOIN消除那些child記錄,爲WH ich有一個location的後代,即child的祖先。

+0

第一個查詢有效,但需要大約1.5秒才能獲取位置。當執行兩個步驟的查詢時:爲父代提取LFT和RGT的時間少於0.01秒,使用LFT> parent.LFT和RGT

+0

第二個查詢也可以工作,但需要3-6秒。我們能否更快地獲得地點?我不介意添加一些緩存值的列以使其更快。 –

+1

首先,確保你有'ID','LFT'和'RGT'的指示。如果你有,對於第一個查詢,從移動的條件'WHERE'條款到'ON'條款可以幫助(雖然它surpises我的MySQL優化器不這樣做的話)。 – Oswald

1

我會嘗試一些像這樣的: -

SELECT b.* 
FROM LOC_TABLE a 
INNER JOIN LOC_TABLE b 
ON a.LFT < b.LFT AND a.RGT > b.RGT 
WHERE a.ID = 10 
AND b.TYPE = 4 

簡單連接。

關於第二個問題,也許這樣的事情。找到父母,然後從中找到正確類型下的所有記錄。找到同一類型的這個孩子的任何父母。如果發現一個,則忽略。

SELECT b.* 
FROM LOC_TABLE a 
INNER JOIN LOC_TABLE b ON a.LFT < b.LFT AND a.RGT > b.RGT 
LEFT JOIN LOC_TABLE c ON c.LFT > b.LFT AND c.RGT < b.RGT AND b.TYPE = c.TYPE 
WHERE a.ID = 10 
AND b.TYPE = 4 
AND c.ID IS NULL 
+0

在第一個例子中,我必須改了''和'B'在'WHERE'條款和它的作品,但我已經提到過這種類型的查詢需要太多的時間來執行〜1.5秒,而我可以用兩個短查詢(0.01 + 0.2秒)獲取相同的信息。至於第二個查詢,它並不適用,但我可以看到它與Oswald的答案几乎相同。所以它也需要3-6秒才能獲取位置。我們可以加快速度嗎? –

+0

我和奧斯瓦爾德一起寫了我的答案,他們非常相似。我會給奧斯瓦爾德的建議添加一個答案,而不是用兩個非常相似的對話來混淆事物。 – Kickstart

+0

順便說一句,想我在的< and >的亂七八糟的條款,因此,一個小問題。現在修復。 – Kickstart