Oracle:如何通过将子查询删除到条件或加入同一张表来提高查询?
Posted
技术标签:
【中文标题】Oracle:如何通过将子查询删除到条件或加入同一张表来提高查询?【英文标题】:Oracle: How to boost query by removing Subquery into Conditions or Join to same table? 【发布时间】:2020-07-10 12:15:29 【问题描述】:我有一个名为 Employee_All 的视图。
这会使用连接从两个(一对多)表中获取数据,其中一些记录被放入单行并显示在所有员工中。 One
有 30,000 条记录,many
是 One
的两倍。
按照简单的查询需要:1 秒返回 50 条记录
SELECT x.*, (SELECT 'NOIFS' FROM DUAL) as TYPE FROM Employee_ALL x
当我添加条件并在 1.81 秒内返回 50 条记录时
SELECT x.*, (SELECT 'NOIFS' FROM DUAL) as TYPE FROM Employee_ALL x
WHERE (x.endDate > sysdate-90 OR x.endDate is null) OR x.lastUpdated >= sysdate-30
fetch first 50 rows only
现在有子查询,这将在 4.14 秒内返回 50 条记录
SELECT x.*, (SELECT USERID FROM Employee_ALL z WHERE UPPER(EMPLOYEEID)=x.leaderEmployeeId ) as managersuserid, (SELECT 'NOIFS' FROM DUAL) as TYPE
FROM Employee_ALL x
WHERE (x.endDate > sysdate-90 OR x.endDate is null) OR x.lastUpdated >= sysdate-30
fetch first 50 rows only
有什么方法可以调整最后一个查询,使其在几秒钟内返回结果,因为我需要针对 30,000 条记录运行此查询? (加载数据大约需要 10-15 分钟)还有什么建议
示例数据如下:
EmpID ManagerEmpID NAME UserID
1 2 Harry Har
2 Garry Manager Gar
3 2 Cherry Char
【问题讨论】:
改为使用左连接。 为什么需要在“id”列上使用UPPER()
?
@GordonLinoff:它似乎是旧代码。
@jarlh:我们如何在上述情况下应用左连接?我遇到了列模棱两可的问题
如果您对两个表进行左连接,则限定每一列
【参考方案1】:
如果不了解整个数据模型以及预期的结果是什么,这是相当困难的。我会使用这个查询:
SELECT x.* ,
case when UPPER(x.EMPLOYEEID)=z.leaderEmployeeId then z.userid else null end
as managersuserid,
'NOIFS' as TYPE
FROM Employee_ALL x left join Employee_ALL z on ( x.EMPLOYEEID = z.EMPLOYEEID )
WHERE (x.endDate > sysdate-90 OR x.endDate is null) OR x.lastUpdated >= sysdate-30
使用您的数据模型示例我构建了这个
SQL> create table Employee_ALL ( EMPLOYEEID number, managerempid number, name varchar2(100) , userid varchar2(100) );
insert into Employee_ALL values ( 1 ,2 , 'Harry' , 'Har' );
insert into Employee_ALL values ( 2 ,null , 'Robert' , 'Rob' );
insert into Employee_ALL values ( 3 ,null , 'Jim' , 'Jim' );
insert into Employee_ALL values ( 4 ,2 , 'Frank' , 'Fra' );
Table created.
SQL> SQL>
1 row created.
SQL>
1 row created.
SQL>
1 row created.
SQL>
1 row created.
SQL> commit;
SQL> alter table Employee_ALL add end_date date ;
Table altered.
SQL> update Employee_ALL set end_date = sysdate where EMPLOYEEID = 1 ;
update Employee_ALL set end_date = sysdate - 91 where employeeid = 4;
update Employee_ALL set end_date = sysdate where end_date is null;
1 row updated.
SQL> SQL>
1 row updated.
SQL> SQL>
2 rows updated.
SQL> commit;
Commit complete.
SELECT x.* ,
2 case when UPPER(x.EMPLOYEEID)=z.ManagerEmpID then z.userid else null end as managersuserid,
3 'NOIFS' as TYPE
4 FROM Employee_ALL x left join Employee_ALL z on ( x.EMPLOYEEID = z.EMPLOYEEID )
5* WHERE (x.end_date > sysdate-90 OR x.end_date is null)
EMPLOYEEID MANAGEREMPID NAME USERID END_DATE MANAGERSUS TYPE
---------- ------------ ---------- ---------- -------- ---------- -----
1 2 Harry Har 20200710 NOIFS
2 Robert Rob 20200710 NOIFS
3 Jim Jim 20200710 NOIFS
SQL>
如果我更新经理字段
SQL> update Employee_ALL set MANAGEREMPID=2 where employeeid=2 ;
1 row updated.
SQL> commit;
Commit complete.
SQL> SELECT x.* ,
case when UPPER(x.EMPLOYEEID)=z.ManagerEmpID then z.userid else null end as managersuserid,
'NOIFS' as TYPE
FROM Employee_ALL x left join Employee_ALL z on ( x.EMPLOYEEID = z.EMPLOYEEID )
WHERE (x.end_date > sysdate-90 OR x.end_date is null)
/ 2 3 4 5 6
EMPLOYEEID MANAGEREMPID NAME USERID END_DATE MANAGERSUS TYPE
---------- ------------ ---------- ---------- -------- ---------- -----
1 2 Harry Har 20200710 NOIFS
2 2 Robert Rob 20200710 Rob NOIFS
3 Jim Jim 20200710 NOIFS
【讨论】:
我们需要经理的用户ID。在上面的例子中。我们需要ManagerUs id,即EmployeeID 2和3的Managerus字段中的Har 您显示 userid 的条件是这个 UPPER(EMPLOYEEID)=x.leaderEmployeeId ,所以leaderemployeeid 与作为经理的员工的employeeid 相同 看起来都是正确的,但为什么我得到 null :(以上是关于Oracle:如何通过将子查询删除到条件或加入同一张表来提高查询?的主要内容,如果未能解决你的问题,请参考以下文章
是否可以在 Oracle10g 中的同一查询中进行插入和删除?