优化SELECT查询以使用大型数据库

时间:2019-11-12 06:19:00

标签: sql

这是我数据库的部分

ID  EmployeeID    Status    EffectiveDate
 1  110545        Active    2011-08-01
 2  110700        Active    2012-01-05
 3  110060        Active    2012-01-05  
 4  110222        Active    2012-06-30
 5  110545        Resigned  2012-07-01
 6  110545        Active    2013-02-12

我想生成选择现役雇员的记录:

ID  EmployeeID    Status  EffectiveDate
 2  110700        Active  2012-01-05
 3  110060        Active  2012-01-05
 4  110222        Active  2012-06-30

因此,我尝试了以下查询:

SELECT *
FROM Employee AS E
WHERE E.Status='Active' AND 
      E.EffectiveDate between'2011-08-01' and '2012-07-02'AND  NOT 
      EXISTS(SELECT * FROM Employee AS E2 
             WHERE E2.EmployeeID = E.EmployeeID AND E2.Status = 'Resigned'
                        AND E2.EffectiveDate between '2011-08-01' and '2012-07-02'
             );

它仅适用于少量数据,但是对于大型数据库却出现超时错误。

您能帮我优化吗?

3 个答案:

答案 0 :(得分:0)

我已尝试使用Case语句实现上述结果集。 希望这会有所帮助。

CREATE TABLE employee_test
(rec NUMBER,
employee_id NUMBER,
status VARCHAR2(100),
effectivedate DATE);


INSERT INTO employee_test VALUES(1,110545,'Active',TO_DATE('01-08-2011','DD-MM-YYYY'));
INSERT INTO employee_test VALUES(2,110545,'Active',TO_DATE('05-01-2012','DD-MM-YYYY'));
INSERT INTO employee_test VALUES(3,110545,'Active',TO_DATE('05-01-2012','DD-MM-YYYY'));
INSERT INTO employee_test VALUES(4,110545,'Active',TO_DATE('30-06-2012','DD-MM-YYYY'));
INSERT INTO employee_test VALUES(5,110545,'Resigned',TO_DATE('01-07-2012','DD-MM-YYYY'));
INSERT INTO employee_test VALUES(6,110545,'Active',TO_DATE('12-02-2013','DD-MM-YYYY'));
COMMIT;


SELECT * FROM(
                        SELECT e.* ,
                        CASE WHEN (effectivedate BETWEEN TO_DATE('2011-08-01','YYYY-MM-DD') AND  TO_DATE('2012-07-02','YYYY-MM-DD')  AND status='Active')
                        THEN 'Y' ELSE 'N' END AS FLAG
                         FROM Employee_Test e)
 WHERE Flag='Y'
 ;

答案 1 :(得分:0)

这是我阅读您的要求的方式:您想显示在​​职员工。为此,请查看其最新条目,即“活动”或“已辞职”。

您要将其限制为一定的时间范围。这可能意味着您希望找到所有已激活的员工,而又没有在该时间范围内立即再次变得不活跃。

因此,首先获取每位员工的最新日期,然后在这些行处于活动状态时留在这些行中。

select *
from employee
where (employeeid, effectivedate) in
(
  select employeeid, max(effectivedate)
  from employee
  where effectivedate between date '2011-08-01' and date '2012-07-02'
  group by employeeid
)
and status = 'active'
order by employeeid;

子查询尝试查找时间范围,然后查看每个员工以查找其最新日期。我将向DBMS提供此索引:

create index idx on employee (effectivedate, employeeid);

主查询要使用employeeid和生效日期再次找到该行,然后查询状态。以上索引可以再次使用。我们甚至可以添加状态以简化查找:

create index idx on employee (effectivedate, employeeid, status);

DBMS是否可以使用此索引。由DBMS决定。我发现它很有可能,因为它可以用于执行查询的所有步骤,甚至包含查询所使用的所有列,因此表本身甚至不必读取。

答案 2 :(得分:0)

我添加了另一个答案以及对该请求的另一种解释。以防万一:-)

该表显示每个员工的状态。员工可以变得活跃,然后退休,然后再次活跃。但是,他们当然不能变得活跃起来,然后再活跃起来,而不会在两者之间退休。

我们正在寻找一个时间范围,希望找到所有活跃但从未退休的员工-无论他们在那个时期退休后是否再次活跃。

这很容易。我们正在寻找在该时间范围内只有一行并且该行处于活动状态的员工。一种方法:

select employeeid, any_value(effectivedate), max(status)
from employee
where effectivedate between date '2011-08-01' and date '2012-07-02'
group by employeeid
having max(status) = 'Active'
order by employeeid;

与我的其他答案一样,合适的索引应该是

create index idx on employee (effectivedate, employeeid, status);

我们想查看日期范围并查看每位员工的状态。