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 条记录,manyOne 的两倍。

按照简单的查询需要: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 中的同一查询中进行插入和删除?

选择同一列两次,但条件不同

oracle 如何把同一个表的同一个字段按条件分成不同的字段查询出来结果集?例如:

关于oracle in 的1000条限制

oracle数据查询时如何定位问题数据

将子查询(不在)重写为加入