Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/oracle/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql oracle反连接替代方案_Sql_Oracle_Anti Join - Fatal编程技术网

Sql oracle反连接替代方案

Sql oracle反连接替代方案,sql,oracle,anti-join,Sql,Oracle,Anti Join,我面临一个问题,我必须从一个表(“子表”)中选择行,该表应该有一个指向另一个表(“父表”)的外键。问题是外键已损坏(长话短说,表已分区,并且由于某些原因存在孤立项),因此我必须在恢复外键之前清理子表。我想做的是(大致): 这似乎是正确的(从结果来看),但是效率很低:有1M个结果,子表可以容纳100M多行。 因为我必须删除来自该查询结果的每一行,所以我使用分页,但afaict这意味着每次都会重复NOT IN查询。 出于这个原因,我想知道是否有任何方法可以提高查询的性能。我已经尝试加入表,但我意识到

我面临一个问题,我必须从一个表(“子表”)中选择行,该表应该有一个指向另一个表(“父表”)的外键。问题是外键已损坏(长话短说,表已分区,并且由于某些原因存在孤立项),因此我必须在恢复外键之前清理子表。我想做的是(大致):

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

每次都不会重复NOT IN查询。查询优化器可能会进行各种优化。然后,对于这样的查询,它可能决定扫描每一行,而不考虑索引,完全基于两个表之间的行数平衡

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

SELECT child.ID 
FROM CHILD child 
LEFT JOIN PARENT parent ON parent.ID = child.PARENT_ID
WHERE parent.ID IS NULL
第三种语法是使用
notexists

SELECT child.ID
FROM CHILD child
WHERE NOT EXISTS (
    SELECT * 
    FROM PARENT parent 
    WHERE parent.ID = child.PARENT_ID
)

这种语法通常效率更高:

select id from child
where
    parent_id in
    (
        select parent_id from child
        minus
        select id from parent
    );
现在,当您要删除子行时,速度会非常慢

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

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


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

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

  • 如果应用了主键约束,则不允许使用空值 允许
  • 当使用唯一约束时,则为空的行 值将不会被视为外部数据库引用的唯一值 钥匙
  • 此外,如果子-父\u id为空,则将忽略外键检查。如果我们想要一个强关系,我们应该对子父\子id应用NOTNULL约束
如果子项允许父项id为空,则可以:

update child
   set parent_id = null 
 where parent_id in (select parent_id from child  
                      minus 
                     select id from parent);
在这种情况下,我们希望使用减号在结果集中应该有少量孤立键

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

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)。如果优化器没有过多的干扰,这是正确的。

注意,
存在
的行为与中的
在空值情况下的行为不同。如果
parent.ID
有任何空值,您将使用
NOT EXISTS
而不是
NOT In
@GolezTrol获得行,我尝试使用
LEFT JOIN
构造,但由于我将在父级主键上加入,因此查询不会返回任何结果(并不是说有空值,行不只是在那里).@WernfriedDomscheit感谢您的添加。在本例中,这不会是一个问题,因为parent.ID是表的主键,但总的来说,这绝对是需要考虑的。@francescoforesti这是左联接的思想,如果第二个表中没有匹配项,仍然返回第一个表中的记录。where子句使re确保只返回那些不匹配的记录。与其他查询一样,该查询应该为您提供所有没有匹配父项的子项的ID。@GolezTrol我知道您是对的,但我尝试了两个查询(不在和左联接),左联接确实返回0(零)结果。所以我不得不得出结论,在这种情况下,它们并不等同(尽管我不知道为什么)父键和子键
是否不为null
?带有null或潜在null值的
不为in
的逻辑可能会迫使优化程序采用效率低下的逐行方法,并且将
不为null
条件添加到联接的两侧可能会有所帮助。不过这有点像猜测-表详细信息和执行计划可能会被忽略lp缩小问题范围。是的,两个字段都有一个NOTNULL约束(父字段是主键,子字段是父字段的外键)。
create table child_orphans as
select *
  from child 
  natural join (select parent_id from child
                 minus 
                select id from parent);