如何在 Oracle 中使用 max in where 子句优化查询
How to optimize query in Oracle with max in where clause
我提供假设 table 和查询来解释我的问题。请原谅我的语法错误。
部门 table:
ID Dno Dname BDate seq
1 1 A 5-Aug 0
2 1 B 3-Aug 0
3 1 B 7-Aug 1
4 1 C 2-Aug 0
下方查询returns 1st, and 3rd, record from above table:
select * from Dept where BDate > (select mydate from other_table)
-- mydate is 4-Aug
然后我在查询中对 return 第二条记录进行了以下更改。因为对于 Dname 'B',我们有一条 Bdate > 4-Aug.
的记录
select * from Dept D where
(SELECT MAX(BDATE)
FROM Dept D1
WHERE D1.Dno = D.Dno
AND D1.Dname = D.Dname
) > (select mydate from other_table)
以上查询有效,但影响了性能。我该如何优化它。
我想到联合或将最大查询移动到 select 部分。但是,找不到方法。
假设我正确理解您的逻辑(如果最大日期大于指定日期,您需要给定 dno 和 dname 的所有行)并且查询检索 "mydate" returns 一行,我会做类似的事情:
with dept as (select 1 id, 1 dno, 'A' dname, to_date('05/08/2015', 'dd/mm/yyyy') bdate, 0 seq from dual union all
select 2 id, 1 dno, 'B' dname, to_date('03/08/2015', 'dd/mm/yyyy') bdate, 0 seq from dual union all
select 3 id, 1 dno, 'B' dname, to_date('07/08/2015', 'dd/mm/yyyy') bdate, 0 seq from dual union all
select 4 id, 1 dno, 'C' dname, to_date('02/08/2015', 'dd/mm/yyyy') bdate, 0 seq from dual),
other_table as (select to_date('04/08/2015', 'dd/mm/yyyy') mydate from dual)
select id,
dno,
dname,
bdate,
seq
from (select d.*,
max(bdate) over (partition by dno, dname) max_bdate
from dept d)
where max_bdate > (select mydate from other_table);
ID DNO DNAME BDATE SEQ
---------- ---------- ----- ---------- ----------
1 1 A 05/08/2015 0
2 1 B 03/08/2015 0
3 1 B 07/08/2015 0
使用 group-by 子句避免其中一个子查询:
select Dno, Dname, max(BDate)
from Dept
group by Dno, Dname
having Max(BDate) > (select mydate from other_table)
您还可以使用本地变量删除其他子查询:
declare @mydate Date = (select mydate from other_table);
select Dno, Dname, max(BDate)
from Dept
group by Dno, Dname
having Max(BDate) > (@mydate)
如果您希望此查询 return 您 DEPT
table 中的一小部分行,这对您来说可能会更快。我假设 DEPT.DNAME
是唯一的并且上面有一个索引。 (当然 DEPT.BDATE
上需要有一个索引!)
with dept as (select 1 id, 1 dno, 'A' dname, to_date('05/08/2015', 'dd/mm/yyyy') bdate, 0 seq from dual union all
select 2 id, 1 dno, 'B' dname, to_date('03/08/2015', 'dd/mm/yyyy') bdate, 0 seq from dual union all
select 3 id, 1 dno, 'B' dname, to_date('07/08/2015', 'dd/mm/yyyy') bdate, 0 seq from dual union all
select 4 id, 1 dno, 'C' dname, to_date('02/08/2015', 'dd/mm/yyyy') bdate, 0 seq from dual),
other_table as (select to_date('04/08/2015', 'dd/mm/yyyy') mydate from dual)
select id,
dno,
dname,
bdate,
seq
from dept WHERE dname IN ( SELECT d2.dname FROM dept d2 WHERE d2.bdate > (select mydate from other_table) );
以下查询运行速度快 4 倍且结果正确:
select d1.* from Dept d1,
(select dno, dname, MAX(BDATE) as maxdate from Dept group by dno, dname) d2
where
d1.dno=d2.dno and d1.dname=d2.dname
and d2.maxdate > (select mydate from other_table)
根据数据集的选择性,可能值得尝试这种方法:
select *
from dept
where (dno, dname) in (
select distinct dno, dname
from dept
where BDATE > (select mydate from other_table))
有了 dept(bdate) 和 dept(dno,dname) 上的索引,并且只匹配很少的记录,这会非常快。
我提供假设 table 和查询来解释我的问题。请原谅我的语法错误。
部门 table:
ID Dno Dname BDate seq
1 1 A 5-Aug 0
2 1 B 3-Aug 0
3 1 B 7-Aug 1
4 1 C 2-Aug 0
下方查询returns 1st, and 3rd, record from above table:
select * from Dept where BDate > (select mydate from other_table)
-- mydate is 4-Aug
然后我在查询中对 return 第二条记录进行了以下更改。因为对于 Dname 'B',我们有一条 Bdate > 4-Aug.
的记录select * from Dept D where
(SELECT MAX(BDATE)
FROM Dept D1
WHERE D1.Dno = D.Dno
AND D1.Dname = D.Dname
) > (select mydate from other_table)
以上查询有效,但影响了性能。我该如何优化它。
我想到联合或将最大查询移动到 select 部分。但是,找不到方法。
假设我正确理解您的逻辑(如果最大日期大于指定日期,您需要给定 dno 和 dname 的所有行)并且查询检索 "mydate" returns 一行,我会做类似的事情:
with dept as (select 1 id, 1 dno, 'A' dname, to_date('05/08/2015', 'dd/mm/yyyy') bdate, 0 seq from dual union all
select 2 id, 1 dno, 'B' dname, to_date('03/08/2015', 'dd/mm/yyyy') bdate, 0 seq from dual union all
select 3 id, 1 dno, 'B' dname, to_date('07/08/2015', 'dd/mm/yyyy') bdate, 0 seq from dual union all
select 4 id, 1 dno, 'C' dname, to_date('02/08/2015', 'dd/mm/yyyy') bdate, 0 seq from dual),
other_table as (select to_date('04/08/2015', 'dd/mm/yyyy') mydate from dual)
select id,
dno,
dname,
bdate,
seq
from (select d.*,
max(bdate) over (partition by dno, dname) max_bdate
from dept d)
where max_bdate > (select mydate from other_table);
ID DNO DNAME BDATE SEQ
---------- ---------- ----- ---------- ----------
1 1 A 05/08/2015 0
2 1 B 03/08/2015 0
3 1 B 07/08/2015 0
使用 group-by 子句避免其中一个子查询:
select Dno, Dname, max(BDate)
from Dept
group by Dno, Dname
having Max(BDate) > (select mydate from other_table)
您还可以使用本地变量删除其他子查询:
declare @mydate Date = (select mydate from other_table);
select Dno, Dname, max(BDate)
from Dept
group by Dno, Dname
having Max(BDate) > (@mydate)
如果您希望此查询 return 您 DEPT
table 中的一小部分行,这对您来说可能会更快。我假设 DEPT.DNAME
是唯一的并且上面有一个索引。 (当然 DEPT.BDATE
上需要有一个索引!)
with dept as (select 1 id, 1 dno, 'A' dname, to_date('05/08/2015', 'dd/mm/yyyy') bdate, 0 seq from dual union all
select 2 id, 1 dno, 'B' dname, to_date('03/08/2015', 'dd/mm/yyyy') bdate, 0 seq from dual union all
select 3 id, 1 dno, 'B' dname, to_date('07/08/2015', 'dd/mm/yyyy') bdate, 0 seq from dual union all
select 4 id, 1 dno, 'C' dname, to_date('02/08/2015', 'dd/mm/yyyy') bdate, 0 seq from dual),
other_table as (select to_date('04/08/2015', 'dd/mm/yyyy') mydate from dual)
select id,
dno,
dname,
bdate,
seq
from dept WHERE dname IN ( SELECT d2.dname FROM dept d2 WHERE d2.bdate > (select mydate from other_table) );
以下查询运行速度快 4 倍且结果正确:
select d1.* from Dept d1,
(select dno, dname, MAX(BDATE) as maxdate from Dept group by dno, dname) d2
where
d1.dno=d2.dno and d1.dname=d2.dname
and d2.maxdate > (select mydate from other_table)
根据数据集的选择性,可能值得尝试这种方法:
select *
from dept
where (dno, dname) in (
select distinct dno, dname
from dept
where BDATE > (select mydate from other_table))
有了 dept(bdate) 和 dept(dno,dname) 上的索引,并且只匹配很少的记录,这会非常快。