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