如果我们只对第一个匹配的子行感兴趣,如何优化Oracle中的JOIN?

问题描述 投票:2回答:2

我有父表让我们说P,Id,Name和Type。

P(
  id (pk),
  name,
  type (type in (1..10) )
)

我有一个引用P的子表,让我们说这个表叫做B:

B (
  id,
  date,
  other columns,
  parent_id
)

现在问题是:表P没有那么多记录,但表B真的很大。如果Type = 3B中的日期将始终与父记录相同。

所以我想从P获取type = 3的所有记录,并从表B获取相应的日期。考虑到B非常大,最好的方法是什么?

我当时想写点什么

Select b.parent_id, p.name, max(b.date)
from B b
join P p on p.id = b.parent_id
group by b.parent_id, p.name
where p.type = 3

这里max(b.date)min(b.date)无关紧要,因为Date是相同的。但表B非常大。选择仅从P并加入B,例如“具有最小ID的子行”,或基本上任何子行,不是更好吗?

Select p.id, p.name, b.date
from P p
join B b on (p.id = b.parent_id and "take only first matching row")
where p.type = 3
sql oracle query-optimization
2个回答
1
投票

尝试一下:

Select p.id, p.name, (select b.date from B where p.id = b.parent_id and rownum = 1) date
from P p
where p.type = 3

1
投票

根据要求,假设您有b (parent_id)的索引。如果您拥有的数据是:

create table p (
  id number(6) primary key not null,
  name varchar2(20),
  type number(2)
);

insert into p (id, name, type) values (10, 'John', 2);
insert into p (id, name, type) values (11, 'Peter', 3);
insert into p (id, name, type) values (12, 'Albert', 3);
insert into p (id, name, type) values (13, 'Mary', 4);
insert into p (id, name, type) values (14, 'Diego', 3);

create table b (
  id number(6),
  date1 date,
  parent_id number(6),
  constraint fk1_b foreign key (parent_id) references p (id)
);

create index ix1_b on b (parent_id);

insert into b (id, date1, parent_id) values (101, timestamp '2018-01-01 12:34:56', 10);
insert into b (id, date1, parent_id) values (102, timestamp '2018-01-02 12:34:57', 11);
insert into b (id, date1, parent_id) values (103, timestamp '2018-01-03 12:34:58', 11);
insert into b (id, date1, parent_id) values (104, timestamp '2018-01-04 12:34:59', 11);
insert into b (id, date1, parent_id) values (105, timestamp '2018-01-04 12:55:10', 12);
insert into b (id, date1, parent_id) values (106, timestamp '2018-01-04 12:55:11', 12);
insert into b (id, date1, parent_id) values (107, timestamp '2018-01-04 12:55:12', 12);

查询将是:

select p.*, bl.date1
  from p,
  lateral (
    select * from b where b.parent_id = p.id fetch next 1 rows only
  ) bl
  where p.type = 3;

结果:

ID  NAME    TYPE  DATE1
--  ------  ----  ---------------------
11  Peter   3     2018-01-02 12:34:57.0
12  Albert  3     2018-01-04 12:55:10.0

现在,如果在p中没有任何行的b中存在行(在我的示例中为“Diego”),则需要外连接:

select p.*, bl.date1
  from p
  outer apply (
    select * from b where b.parent_id = p.id fetch next 1 rows only
  ) bl
  where p.type = 3;

结果:

ID  NAME    TYPE  DATE1
--  ------  ----  ---------------------
11  Peter   3     2018-01-02 12:34:57.0
12  Albert  3     2018-01-04 12:55:10.0
14  Diego   3     <null>

干杯!

© www.soinside.com 2019 - 2024. All rights reserved.