2011-04-21 79 views
2

我有一個查詢選擇節點表,然後加入一個標題表。這是通過首先加入節點ID和標題ID之間的中間表來完成的,這允許前兩個表之間的多對多關係。兩個連接都是內聯的,因此只有具有正確配置和現有標題的節點才被選中。我相信這一切都是乾淨和高效的 - 問題如下:快速查詢選擇不在MySQL的另一個表中的所有記錄

還有第四個表,它爲節點提供了一個簡單的層次結構; node_parents。每行有兩個字段;節點ID和充當該節點的父節點的節點ID(node_id和parent_id)。有些節點沒有在此數據庫中配置子節點(即節點本身未在node_parents表的任何行中標記爲父節點) - 這些是我試圖選擇的節點。

這些無子節點的附加標準是它們有一個特定的標題配置 - 因此子查詢最初從node_titles選擇,然後內部加入node_parents。子查詢也有一個GROUP BY,因爲有些節點是多個節點的父節點,所以它們的node_id將不必要地出現在結果中多次。我還應該指出,正因爲如此,node_parents的主鍵是node_id和parent_id的組合。

查詢:

SELECT `nodes`.`node_id`, 
     `titles`.`title` 
FROM `nodes` 
INNER JOIN `node_titles` 
ON `nodes`.`node_id` = `node_titles`.`node_id` 
INNER JOIN `titles` 
ON `node_titles`.`title_id` = `titles`.`title_id` 
WHERE `nodes`.`node_id` NOT IN 
    (
    SELECT `node_titles`.`node_id` 
    FROM `node_titles` 
    INNER JOIN `node_parents` 
    ON `node_titles`.`node_id` = `node_parents`.`parent_id` 
    WHERE `node_titles`.`title_id` = 1 
    GROUP BY `node_titles`.`node_id` 
    ) 
AND `titles`.`title_id` = 1 

表尺寸: 節點=〜32000個 node_titles =〜49000個 標題= 3個 node_parents =〜55000

的查詢接受約16分鐘來完成。任何人都可以提供任何指針?我曾嘗試剖析查詢 - 這沒有任何長掛,但它確實重複這個循環什麼好像每次選定行:

| executing      | 0.000005 | 
| Copying to tmp table   | 0.515815 | 
| Sorting result     | 0.000053 | 
| Sending data     | 0.000028 | 

我也曾嘗試開溝子查詢和使用LEFT JOIN與一個WHERE foo不是NULL,但是這仍然需要很長時間來處理 - 分析器宣稱'複製到tmp表'的時間爲180秒。

最終我懷疑這可能是一個索引問題 - 但無論哪種方式,我都會欣賞不會質疑查詢實現的答案,除非他們正在追求可能的放緩原因(例如,是,標題和節點必須處於多對多關係)。謝謝大家,並提供更多信息!

+0

您當前的查詢只有在定義了'title = 1'(可能沿着其他標題)時纔會選擇無子節點。那是你想達到的目標嗎? – Quassnoi 2011-04-21 11:44:36

+0

@Quassnoi對不起,忘了在主要查詢中包含一個附加的where子句,它應該停止有子節點的節點被選中。 – tjbp 2011-04-21 12:04:24

+0

查看查詢更新。 – Quassnoi 2011-04-21 12:18:42

回答

2

從子查詢中刪除GROUP BY

SELECT nodes.node_id, 
     titles.title 
FROM nodes n 
INNER JOIN 
     node_titles nt 
ON  nt.node_id = n.node_id 
INNER JOIN 
     titles t 
ON  t.title_id = nt.title_id 
WHERE n.node_id NOT IN 
     (
     SELECT nti.node_id 
     FROM node_titles nti 
     INNER JOIN 
       node_parents npi 
     ON  npi.parent_id = nt.node_id 
     WHERE nti.title_id = 1 
     ) 

創建以下指標:

node_titles (node_id, title_id) 
titles (title_id) 
node_parents (parent_id) 

更新:

試試這個:

SELECT nodes.node_id, 
     titles.title 
FROM nodes n 
INNER JOIN 
     node_titles nt 
ON  nt.node_id = n.node_id 
     AND nt.title_id = 1 
INNER JOIN 
     titles t 
ON  t.title_id = nt.title_id 
WHERE n.node_id NOT IN 
     (
     SELECT parent_id 
     FROM node_parents 
     ) 
+0

非常感謝,這完美的作品。我有除了在node_parents上的那些索引。一旦GROUP BY被刪除,查詢花了0.3秒。真棒!再次感謝 :) – tjbp 2011-04-21 12:22:30

1

根據我的經驗,MySql往往會遇到子查詢問題。試試這個

SELECT nodes.node_id, 
     titles.title 
FROM nodes b 
INNER JOIN 
     node_titles nt 
ON  nt.node_id = n.node_id 
INNER JOIN 
     titles t 
ON  t.title_id = nt.title_id 
LEFT OUTER JOIN 
     (
     SELECT nti.node_id 
     FROM node_titles nti 
     INNER JOIN 
       node_parents npi 
     ON  npi.parent_id = nt.node_id 
     WHERE nti.title_id = 1 
     ) ThisTable on n.node_id = ThisTable.node_id 
WHERE ThisTable.node_id is null 
相關問題