oracle sql - 删除每个组的值为null的行

时间:2014-01-05 12:33:53

标签: sql performance oracle

我尝试在邮件列中删除具有空值的行,当且仅当存在具有相同person_id的非空值的行时。

DELETE
FROM
  EMP_MAIL EM
WHERE
  MAIL IS NULL
AND EXISTS
  (
    SELECT 
      EMP_ID
    FROM
      EMP_MAIL EM2
    WHERE
      MAIL IS NOT NULL
    AND EM.EMP_ID    = EM2.EMP_ID
  ) ;

但需要很长时间。 (我在EMP_MAIL(EMP_ID)上有一个非唯一索引)

是否有更好的方法来执行此操作?

2 个答案:

答案 0 :(得分:0)

这取决于您的输入数据,我希望此查询可以帮助您或为您提供一些解决问题的线索:

DELETE
from 
EMP_MAIL t1 
where 
t1.MAIL is null and 
not Exists
(select t2.EMP_ID from (select EMP_ID from EMP_MAIL where mail is not null
minus
select EMP_ID from EMP_MAIL where mail is null)t2 where t1.EMP_ID =t2.EMP_ID);

答案 1 :(得分:0)

好吧,我已经测试了一下,现在我将展示结果。

这是我的测试脚本(看看:根本没有索引):

create table emp_mail (
  emp_id        number,
  mail          clob
);

declare
  amount_of_users        constant number := 30000;
  nulls_amount_percent   constant number := 90;
begin
  for i in 1..300 loop
    insert into emp_mail
    select round(dbms_random.value*amount_of_users),case when dbms_random.value < nulls_amount_percent/100 then null else 'some mail' end
    from dual
    connect by level <= 10000;

    commit;
  end loop;
end;
/
delete from emp_mail em
where mail is null
  and exists (select null
              from emp_mail em2
              where mail is not null
                and em.emp_id = em2.emp_id);

drop table emp_mail;

它创建了表(我使用CLOB创建最坏的情况),然后用常量填充表中的3M行

  amount_of_users        constant number := 30000;
  nulls_amount_percent   constant number := 90;

您可以围绕要删除的行进行播放,然后执行“删除”语句并删除该表。

我们来谈谈数字。

警告:当我谈到秒时我的意思是只删除语句,因为行生成器匿名块需要将近2分钟。

使用这些值

  amount_of_users        constant number := 30000;
  nulls_amount_percent   constant number := 90;

几乎整个表都被删除了,我可以重现你的神秘主义者27.5秒。

然后我拿

  amount_of_users        constant number := 30000;
  nulls_amount_percent   constant number := 1;

减少删除的行数,它只给我1.8秒。

让我们假设没有删除任何行:

  amount_of_users        constant number := 30000;
  nulls_amount_percent   constant number := 0;

猜猜时间? 1.1秒,据你所知,这是你的情况。

好吧,我不能给你任何建议做什么,因为你说的话可能比一个查询更全局。也许,您的数据库版本太旧了,或者它是关于硬件或其他任何东西。

如果是关于这种情况

  amount_of_users        constant number := 30000;
  nulls_amount_percent   constant number := 90;

当删除了很多行时,我可以建议将删除拆分为例如10000行部分(首先选择count(*)以了解应该运行限制删除的次数)并在每次执行后进行提交,有时候删除大量行会快得多。但是,据你所知,你删除了0行,这不应该是你的问题。