我们有一些表可以跟踪已处理的交易。这些表有数百万行。通常我想查看最近的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首先执行嵌套查询?可能通过使用提示?
由于
答案 0 :(得分:2)
您的方法可能会阻止从反式中选择最多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
答案 1 :(得分: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;
答案 2 :(得分: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)
答案 3 :(得分: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;
答案 4 :(得分:0)
您可以简单地过滤主要转换表中的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;