5

首先注意我见过这个问题:TSQL delete with an inner join

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

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

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

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

TSQL 正在将其制成正确的反半联接并在索引上做得很好。问题是它创建了一个要删除的内容列表,然后在执行删除时再次执行相同的检查。

我想我的问题是是否有逐行尝试删除,(我不打算在游标中这样做,因为我知道它会有多慢),但你会认为这样的关键字会存在,我没有t 有运气找到它虽然。

4

6 回答 6

2

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

(不可行的想法):如果这是一个主要问题,您可以尝试某种引用计数实现,使用触发器来更新计数器 - 但实际上我希望这将比简单地检查更多开销来维护像你一样的钥匙。

您也可以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

再一次 - 我强调这应该只从管理脚本之类的东西中运行。

于 2009-07-06T07:24:59.187 回答
1

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

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

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

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

于 2009-07-06T09:04:23.510 回答
0

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

我希望这对你有用!

于 2009-07-06T07:34:42.460 回答
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
于 2009-06-29T08:09:32.927 回答
0

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

于 2009-06-29T08:15:45.083 回答
0

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

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

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

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

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

于 2009-07-06T08:25:16.710 回答