如何避免Rownum?

时间:2014-09-04 07:59:58

标签: sql oracle oracle11g oracle10g

由于批量限制,以下查询会选取1000行,并且只能获取1000行。 如果我不使用rownum,它只需要5秒即可获得超过1000个recs ..但是使用rownum需要20秒。

SELECT  E.INFO_ID
FROM TAB1 E LEFT OUTER JOIN TAB2 D
ON E.INFO_ID= D.INFO_ID 
WHERE D.INFO_ID IS NULL AND ROWNUM < 1000;

请帮助我调整查询而不影响功能。

1 个答案:

答案 0 :(得分:1)

查看执行计划。可能优化器认为它可以通过遵循不同的路径来更快地获得前1000个结果,对于使用散列连接等的完整数据,它可以在第一个记录上快速地显示出来。

了解执行计划后,您可以使用提示让优化程序按照您的经验更好地遵循路径。

无论如何,你要求在tab2中不存在的tab1记录,而不是用NOT EXISTS,NOT IN或MINUS这样说,你可以通过左连接来隐藏它。这个有时可以更快,但毕竟它是一个技巧。为什么不以更直接的方式重新编写查询并查看它的执行情况?我认为这样的声明对于使用rownum限制等轻微改动可能会更稳定。值得一试。

编辑:一些澄清。您要求在tab1中存在但在tab2中不存在的ID。这将是:

SELECT INFO_ID FROM TAB1 
MINUS
SELECT INFO_ID FROM TAB2;

您还可以区别对任务进行说明,例如:我希望tab1中的所有ID都不存在于tab2中:

SELECT INFO_ID FROM TAB1
WHERE NOT EXISTS 
(
  SELECT * FROM TAB2
  WHERE TAB2.INFO_ID = TAB1.INFO_ID
);

或者:我希望tab1中的所有ID都不在tab2

SELECT INFO_ID FROM TAB1
WHERE INFO_ID NOT IN
(
  SELECT INFO_ID FROM TAB2
);

您要做的是说:对于tab1中的每个ID,在tab2中找到所有匹配的ID并组合这些ID。对于选项卡1中在tab2中没有匹配的ID,也给我一个结果记录。然后从那个(可能是巨大的)结果集删除所有匹配,以便我留下那些没有匹配的ID。

许多词来描述同一个任务。因此,对于不熟悉这种技巧技术的人来说,查询不容易阅读。查询肯定会产生一个大的中间结果。那么为什么人们会使用它呢?数据库系统随着连接而增长,所以这是他们真正擅长的东西。例如,他们使用哈希机制来获取记录,而不是循环记录记录。因此,尽管提出了相当复杂的访问方式,左连接技术可能会带来良好的性能。

但是,上述查询更直截了当。让我们来看看第一个;可能的执行计划是:订单tab1 ID,Order tab2 ID,然后循环一次以保持tab1 ID与tab2匹配。非常简单。排序需要时间,但随后你会对两个结果进行分析。如果这种情况很快就会给你第一千次匹配,那么当你用ROWNUM&lt;来限制结果时,很可能会这样做。 1000.第二个查询?循环通过tab1并使用id给出在tab2中找到匹配项,如果没有,则保留该记录。索引可能很快,并且添加ROWNUM&lt; 1000可能不会改变获取第一个记录的速度,因为执行路径保持不变。第三个查询:可以像第二个一样解释。或者tab2 ID被放入一个具有快速访问权限的数组中。无论如何,ROWNUM&lt; 1000在访问路径中不太可能发生太大变化。

但是您的查询很难说。当所有记录必须被视为ahash join可能是最快的。但如果只有一些记录就足够了,为什么要加入一切呢?也许优化器决定按tab1的记录进行记录,然后在tab2中查找匹配。这将极大地改变执行计划,并且可以对前1000条记录更快。它不能保证是这样,运气不好,因为在你的情况下,它甚至会变慢。

毕竟,Oracle有一个很好的优化器。查询被重写,您的查询可能会变成NOT EXISTS查询,反之亦然。即使没有重写:尽管处理不同的查询,优化器仍然可以决定相同的执行计划。所以你永远不会知道。但它总是值得一试。

我的建议:编写直接的SQL。通常,SQL语句可以类似于如何用单词表达它的任务。如上所示。只有在遇到性能问题时,才会想到如何重新编写查询来处理这个问题。