我有一个这样的SQL查询:
select w.name, c.address, b.salary, a.product, d.contract_amount
from w
left join c c.id = w.id
left join b b.id = w.id
left join a a.id = w.id and a.date > sysdate-30
left join d d.id = w.id
where w.id = '12345';
这是计划:
-----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost | Time |
-----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 849 |18896868| 00:01:14 |
| 1 | NESTED LOOPS OUTER | | 1 | 849 |18896868| 00:01:14 |
| 2 | NESTED LOOPS OUTER | | 1 | 849 |18896868| 00:01:14 |
| 3 | NESTED LOOPS OUTER | | 1 | 670 |18896868| 00:01:14 |
| 4 | NESTED LOOPS OUTER | | 1 | 596 |18896868| 00:01:14 |
| 5 | TABLE ACCESS STORAGE FULL | w | 1 | 415 | 20 | 00:00:01 |
| 6 | TABLE ACCESS BY INDEX ROWID | c | 1 | 22 | 3 | 00:00:01 |
| 7 | INDEX UNIQUE SCAN |c_id_nd| 1 | | | 00:00:01 |
| 8 | TABLE ACCESS BY INDEX ROWID | b | 1 | 66 | 2 | 00:00:01 |
| 9 | INDEX UNIQUE SCAN |b_id_nd| 1 | | | 00:00:01 |
| 10 | TABLE ACCESS BY INDEX ROWID | a | 1 | 11 | 3 | 00:00:01 |
| 11 | INDEX UNIQUE |a_id_nd| 1 | | | 00:00:01 |
| 12 | TABLE ACCESS BY INDEX ROWID | d | 1 | 25 | 1 | 00:00:01 |
| 13 | INDEX UNIQUE |d_id_nd| 1 | | | 00:00:01 |
-----------------------------------------------------------------------------------
现在它的工作大约需要15-18秒,而且太长了。我是调优的新手,我不知道如何提高其性能。实际上,所有表都有大约33-54百万行,所有id列都有索引。还统计了表的统计信息,我不能使用并行提示。 我该怎么做?
答案 0 :(得分:1)
对于此查询:
select w.name, c.address, b.salary, a.product, d.contract_amount
from w left join
c
on c.id = w.id left join
b
on b.id = w.id left join
a
on a.id = w.id and a.date > sysdate-30 left join
d
on d.id = w.id
where w.id = '12345';
您要在w(id)
,c(id),
b(id), a(id, date)
和d(id)
上建立索引。
答案 1 :(得分:0)
表中有3500万条记录。表是否已分区?如果是这样,查询将确保分区修剪
答案 2 :(得分:0)
我想您的查询没有问题,我认为最初生成的执行计划很糟糕,它仍然位于缓存中。您可以用其他方式覆盖查询,可能会得到更好的计划(例如CTE)。您也可以尝试在加入前过滤ID。尝试这样的东西
with
W as (select id, name from w where w.id = '12345')
,C as (select id, address from C where c.id = '12345')
,B as (select id, salary from B where b.id = '12345')
,A as (select id, product from A where a.id = '12345' and a.date > sysdate - 30)
,D as (select id, contract_amount from D where d.id = '12345')
select w.name, c.address, b.salary, a.product, d.contract_amount
from w
left join c on c.id = w.id
left join b on b.id = w.id
left join a on a.id = w.id
left join d on d.id = w.id
或者这个:
with
W1 as (select w.id, w.name from w where w.id = '12345')
,W2 as (select w1.* , c.address from W1 left outer join C on w1.id = c.id)
,W3 as (select w2.*, b.salary from W2 left outer join B on w2.id = b.id)
,W4 as (select w3.*, a.product from W3 left outer join A on w3.id = a.id and a.date > sysdate - 30)
Select w4.*, d.contract_amount from W4 left outer join D on w4.id = d.id
答案 3 :(得分:0)
我认为问题出在基数估计器上。由于从主表到详细信息“类型”表的多个左联接,因此错误地假定了行返回。基数估计不正确可能会导致计划选择不正确。我建议尝试使用Mike建议的隔离选择并比较计时。我不确定智能CTE在Oracle中的表现如何,因此即使您必须使用临时表或内存表,我也建议您使用绝对隔离的语句。使用您的id值单独选择每个表,然后将结果放入临时表中。然后在这些临时表上执行最终选择。