来自NOT IN查询的MySQL Beach Ball

时间:2009-11-28 23:33:58

标签: mysql select crash

我有两个查询,每个查询返回一个节点ID列表

SELECT node.nid 
  FROM dpf_node AS node 
 WHERE node.type = 'image' AND node.nid; 

SELECT node.nid 
  FROM dpf_node AS node, dpf_image_galleries_images AS image 
 WHERE image.image_nid = node.nid  
   AND node.type = 'image'
   AND image.gallery_nid = 138;

这两个都正常工作

最终虽然我想得到第一个结果列表而不是第二个结果列表中的节点ID列表,但我一直在使用这个查询:

SELECT node.nid 
  FROM dpf_node AS node 
 WHERE node.type = 'image' 
   AND node.nid NOT IN (SELECT node.nid 
                          FROM dpf_node AS node, dpf_image_galleries_images AS image 
                         WHERE image.image_nid = node.nid 
                           AND node.type = 'image' 
                           AND image.gallery_nid = 138);

有一段时间这个工作正常,但就在今晚,它正在沙滩上投球,并导致阿帕奇陷入停顿。我怀疑(/希望)清除数据并重新开始将解决它但是真的想要解决真正的问题,以防它在系统运行后重新抬头。

3 个答案:

答案 0 :(得分:1)

将其更改为NOT EXISTS查询以帮助提高效果:

SELECT node.nid 
  FROM dpf_node AS node 
 WHERE node.type = 'image'
       AND NOT EXISTS (
         SELECT 1
         FROM dpf_node AS i_node
         JOIN dpf_image_galleries_images AS image ON i_node.nid = image.image_nod
         WHERE node.type = 'image'
         AND image.gallery_nid = 138
         AND i_node.nid = node.nid
       )

您还应验证您是否有足够的索引。

答案 1 :(得分:1)

MySQL可能在使用相关子查询时做了相当愚蠢的事情(查看查询计划)。 如果您只想要第一个查询中不在第二个查询中的内容,则可以通过两个LEFT OUTER JOIN获得明显更好的性能,并使用筛选条件筛选出具有第二组结果的空值的行。 / p>

答案 2 :(得分:0)

你应该能够用一个选择来做到这一点。您可以排除它们,而不是选择您不想要的所有节点,而是首先选择您想要的节点。如果图像库和节点之间可能存在许多关系,并且您只需要唯一的node.nids,则将其设置为select distinct。

SELECT node.nid
FROM dpf_node AS node
JOIN dpf_image_galleries_images AS image 
    ON node.nid = image.image_nod
WHERE node.type = 'image'
AND image.gallery_nid != 138

根据数据的布局方式和数据量,这应该比where子句子查询好得多。而且它更容易理解。