如果行不受约束影响,则删除SQL

时间:2009-06-29 07:53:19

标签: sql entity-relationship

首先请注意,我已经看到了这个问题:TSQL delete with an inner join

我有一个大表和几个外键关系,每个关系都有给定年龄的数据。我们需要定期删除比给定数据更早的数据,以阻止数据库无限制地增长。

我正在编写一个查询,如果您按照给定的参数将从星上的每个点删除(不幸的是,这些是可配置的,并且表之间不同)。

在第一次删除之后,我有一个中央表,我担心我正在做两次尝试删除的工作,就像删除数据库检查条件一样。我有一套:

AND NOT EXISTS
(SELECT key 
FROM table 
WHERE table.key = centretable.key)

哪个TSQL正在进行正确的反半连接并在索引上做得很好。问题是它创建了一个要删除的东西列表,然后再次执行相同的检查。

我想我的问题是是否有按行删除,(我不会在游标中这样做,因为我知道它会有多慢),但你会认为这样的关键字会存在,我找不到任何运气。

6 个答案:

答案 0 :(得分:2)

就单个命令而言,它只检查一次关系(而不是在你的例子中检查两次 - 一次用于NOT EXISTS,一次用于DELETE),那么我希望答案很大胖不,抱歉。

(脱离墙壁的想法): 如果这是一个主要问题,你可以尝试某种引用计数实现,使用触发器来更新计数器 - 但实际上我希望这将比维护你已经存在的密钥更多的维护开销。 / p>

您还可以在删除期间调查NOCHECK(因为您自己检查);但你只能在表级执行此操作(管理脚本可能没问题,但生产代码也没有) - 即:

-- disable
alter table ChildTableName nocheck constraint ForeignKeyName

-- enable
alter table ChildTableName check constraint ForeignKeyName

快速测试表明,启用它后,它会对外键执行额外的聚簇索引扫描;如果禁用它,则省略。

这是一个完整的例子;您可以查看两个DELETE操作的查询计划...(理想情况下与其余代码隔离):

create table parent (id int  primary key)
create table child (id int  primary key, pid int)
alter table child add constraint fk_parent foreign key (pid)
    references parent (id)

insert parent values (1)
insert parent values (2)
insert child values (1,1)
insert child values (2,1)

-- ******************* THIS ONE CHECKS THE FOREIGN KEY
delete from parent
where not exists (select 1 from child where pid = parent.id)

-- reset
delete from child
delete from parent
insert parent values (1)
insert parent values (2)
insert child values (1,1)
insert child values (2,1)

-- re-run with check disabled
alter table child nocheck constraint fk_parent

-- ******************* THIS ONE DOESN'T CHECK THE FOREIGN KEY    
delete from parent
where not exists (select 1 from child where pid = parent.id)

-- re-enable
alter table child check constraint fk_parent

再次 - 我强调这应该仅从管理脚本等内容开始。

答案 1 :(得分:1)

您可以创建选择句子的索引视图:

SELECT key FROM table WHERE table.key = centretable.key

索引视图是数据的物理副本,因此检查速度非常快。

您确实需要更新视图的开销,因此您需要根据使用模式对此进行测试。

答案 2 :(得分:0)

如果您正在重复使用相同的东西列表进行删除,那么可以考虑将删除的密钥插入到临时表中,然后在第二个查询中使用它。

SELECT Key, ...
INTO #ToDelete
FROM Table T
WHERE ...

然后是这样的

...
LEFT OUTER JOIN #ToDelete D
ON T.Key=D.Key
WHERE D.Key IS NULL

DROP #ToDelete

答案 3 :(得分:0)

如果在数据库中创建表时将外键指定为约束,则可以通过设置删除规则告诉数据库在删除时要执行的操作。此规则指定当用户尝试删除包含外键关系中的数据的行时会发生什么。 “无操作”设置告诉用户不允许删除并回滚DELETE。像这样实现它会让你在删除它之前自己检查它,因此可以看作是某种尝试。 好吧,至少它的工作原理与MS SQL相同。 http://msdn.microsoft.com/en-us/library/ms177288.aspx

答案 4 :(得分:0)

我找到了一篇讨论在删除中使用外连接的文章: http://www.bennadel.com/blog/939-Using-A-SQL-JOIN-In-A-SQL-DELETE-Statement-Thanks-Pinal-Dave-.htm

我希望这适合你!

答案 5 :(得分:0)

对你的问题的简短回答是否定的,当所有外键引用消失时,没有标准的RDBMS关键字用于删除记录(当然没有一个可以解释外键中的外键)多个表)。

您最有效的选项是根据需要运行的第二个查询,根据每个具有外键的表的一系列NOT EXISTS()子句从“center”中删除。

这是基于我认为对你的情况都适用的两个陈述:

  1. 您将删除比“中心”(父)记录更多的“相关”记录。因此,每次尝试从其他表中删除“中心”时调整“中心”的任何操作都将导致“中心”的即时更新,但需要大量浪费查询才能删除“中心” “偶尔记录。

  2. 鉴于“中心”星上有多个点,任何“浪费的努力”检查其中一个中的外键与整体相比是最小的。例如,如果在从“中心”删除之前要检查四个外键,则最多只能保存25%的时间。