1

我面临一个问题,我必须从表('CHILD')中选择应该具有指向另一个表('PARENT')的外键的行。问题是外键坏了(长话短说,表是分区的,由于某种原因有孤儿),我必须在恢复外键之前清理子表。我想做的是(大致):

SELECT child.ID 
from CHILD child 
WHERE child.PARENT_ID NOT IN 
(
  SELECT parent.ID FROM PARENT parent 
);

这似乎是正确的(从结果来看),但是效率很低:有 1M 个结果,子表包含 100M+ 行。由于我必须删除来自该查询结果的每一行,因此我正在使用分页,但这意味着每次都重复 NOT IN 查询。出于这个原因,我想知道是否有任何方法可以提高查询的性能。我已经尝试加入表格,但我意识到它不会起作用,因为我应该加入child.PARENT_ID = parent.ID,所以不会有结果。所以问题是:有没有办法重写 NOT IN 查询以提高性能?

4

3 回答 3

2

not in 查询不会每次都重复。查询优化器可能会进行各种优化。再说一次,对于这样的查询,它可能决定扫描每一行,而不考虑索引,纯粹基于两个表之间的行数之间的平衡。

您也可以将它写成LEFT JOIN如下所示的形式,但可以说它更难阅读,因为它不能很好地传达意图(尽管这本身并不坏,因为这只是一次性工作)。优化器很可能只是将其视为相同的查询。

SELECT child.ID 
FROM CHILD child 
LEFT JOIN PARENT parent ON parent.ID = child.PARENT_ID
WHERE parent.ID IS NULL

第三种语法是使用NOT EXISTS.

SELECT child.ID
FROM CHILD child
WHERE NOT EXISTS (
    SELECT * 
    FROM PARENT parent 
    WHERE parent.ID = child.PARENT_ID
)
于 2017-12-28T08:26:03.530 回答
1

我认为在这种情况下没有必要考虑空值。如果将外键约束应用于子 parent_id 列,则父对应列上应该有主键或唯一约束。

  • 如果应用主键约束,则不允许空值。
  • 当使用唯一约束时,具有空值的行将不会被视为外键引用的唯一值。
  • 此外,如果 child parent_id 为 null,则将忽略外键检查。如果我们想要一个强关系,我们应该对子 parent_id 应用 NOT NULL 约束。

如果 child 允许在 parent_id 中使用空值,您可以:

update child
   set parent_id = null 
 where parent_id in (select parent_id from child  
                      minus 
                     select id from parent);

在这种情况下,我们希望使用减号在结果集中应该有少量的孤键。

如果 parent_id 具有非空约束,则使用相同的语法删除行

delete child
 where parent_id in (select parent_id from child  
                      minus 
                     select id from parent);

在对子表进行任何更改之前备份孤儿可能是个好主意。

create table child_orphans as
select *
  from child 
  natural join (select parent_id from child
                 minus 
                select id from parent);

这是有效的,因为减法运算的结果集很小,还因为使用内连接而不是半连接(in)。如果优化器没有过多干扰,这是正确的。

于 2018-06-05T12:39:56.013 回答
0

这种语法通常效率更高:

select id from child
where
    parent_id in
    (
        select parent_id from child
        minus
        select id from parent
    );

现在,当您要删除子行时,这将非常缓慢。

相反,为您要保留的子记录构建一个新表,然后重命名或删除旧的子表(先备份!)并将新的子表重命名为 child 会更快。

如果您随后创建主键和外键约束,您将不会再获得任何断开的链接。

我也担心你提到分页。我不确定你的意思,但这听起来相当手动,这对于一百万行是不可行的。

于 2017-12-28T10:06:12.620 回答