0

我们有一些表可以跟踪已处理的事务。这些表有数百万行。很多时候我想查看最近的 X 事务,所以我有一个这样的查询来从几个表中提取我想要的信息:

select a.id, b.field_one, c.field_two
from trans a, table_two b, table_three c
where a.id = b.id
and a.id = c.id
and a.id in
  (select id from trans where id > (select max(id) from trans) - 100);

现在查询很慢。解释计划显示了对 B 和 C 的全表扫描。现在,如果我分别评估嵌套查询并将其替换为逗号分隔的 ID 列表,则查询非常快。这对我来说似乎很明显 - 它只有 100 行可以连接在一起,所以它当然会比通过首先将 A 和 B 连接在一起来回答查询要快。

从概念上讲,我理解查询优化器正在尝试找到一个好的执行计划,但在这种情况下,它似乎做得很糟糕。有什么方法可以强制 DBMS 先执行嵌套查询?可能通过使用提示?

谢谢

4

5 回答 5

2

您可以使用 NO_MERGE 提示,这将强制 Oracle 首先执行内部查询,而不是尝试合并两个查询。这是一个例子:

SELECT /*+NO_MERGE(seattle_dept)*/ e1.last_name, seattle_dept.department_name 
  FROM employees e1, 
    (SELECT location_id, department_id, department_name 
       FROM departments 
      WHERE location_id = 1700) seattle_dept 
  WHERE e1.department_id = seattle_dept.department_id;



select /*+ no_merge(inner) */ a.id, b.field_one, c.field_two
  from trans a, 
       table_two b, 
       table_three c, 
       (select id from trans where id > (select max(id) from trans) - 100) inner
 where a.id = b.id
   and a.id = c.id
   and a.id = inner.id;
于 2013-09-17T20:12:26.123 回答
2

您的方法可能掩盖了这样一个事实,即从 trans.xml 中最多只能选择 100 行。

尝试这个:

with cte_last_trans as (
  select id
  from   (select   id
          from     trans
          where    id > (select max(id)-100 from trans)
          order by id desc)
  where  rownum <= 100)
select a.id,
       b.field_one,
       c.field_two
from   cte_last_trans a,
       table_two      b,
       table_three    c
where  a.id = b.id
and    a.id = c.id

顺便说一句,您是否考虑过并非所有 id 值都存在的可能性?如果要返回 100 行,请使用:

with cte_last_trans as (
  select id
  from   (select   id
          from     trans
          order by id desc)
  where  rownum <= 100)
select a.id,
       b.field_one,
       c.field_two
from   cte_last_trans a,
       table_two      b,
       table_three    c
where  a.id = b.id
and    a.id = c.id
于 2013-09-17T18:29:31.353 回答
0
  select a.id, b.field_one, c.field_two
 from trans a, table_two b, table_three c
 where a.id = b.id
 and a.id = c.id
 and a.id between (select max(id)-100 from trans) and (select max(id) from trans)
于 2013-09-17T18:08:11.263 回答
0

in 似乎没有做任何事情你试过删除它吗?

select a.id, b.field_one, c.field_two
from trans a, table_two b, table_three c
where a.id = b.id
and a.id = c.id
and a.id > (select max(id) from trans) - 100;
于 2013-09-17T18:09:24.117 回答
0

您可以简单地过滤主 trans 表本身中的 100 条记录,而不是一次又一次地加入它。

select a.id, b.field_one, c.field_two
from 
(select id from (select id, row_number() over(order by id desc) rn 
from trans) where rn <=100) a, 
table_two b, table_three c
where a.id = b.id
and a.id = c.id;
于 2013-09-18T06:43:05.747 回答