2011-04-21 76 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 
相关问题