2011-09-22 70 views
1

我有3个表,第一个,table1,作为主键的ID列,第二个表(table2)有一个列table1_id作为外键引用table1.id,第三个表(表3)具有作为表2的列table1_id,其作为外键指向table1.id。如何优化这个SQL删除语句

我已经从删除表1,其中table1.id不table2.table1_id而不是在table3.table1_id

现在

我使用此查询的所有行:

DELETE FROM table1 
WHERE table1.id IN (SELECT table1.id 
        FROM (table2 
          RIGHT OUTER JOIN table1 
           ON table2.table1_id = table1.id) 
          LEFT OUTER JOIN table3 
           ON table3.table1_id = table1.id 
        WHERE table2.table1_id IS NULL 
          AND table3.table1_id IS NULL); 

但非常慢,需要很多时间,这个删除语句有更好的方法吗?

如果这可以帮助我可以假设table2有更多的数据table3。

我使用的数据库是Apache Derby。

感谢您的帮助。

+0

在DBA.stackexchange.com上可能会更好,我们觉得呢? –

+0

为什么downvote?这个问题出了什么问题? – res1

+4

@格雷B,不,我不认为dba是它的地方。这对于管理问题更是如此。这是一个SQL问题,因此属于这里。 – HLGEM

回答

1

假设你得到了明显的覆盖(对于table1.idtable2.table1_idtable3.table1_id创建索引),则无需进行完全外部连接只是为了测试一个关键是在另一张表,你可以使用子查询和exists() - 或not exists()在你的情况。

而且因为你只是在测试的存在,你可以使用下面的模式:

where not exists (select top 1 1 from... where...) 
+0

这是正确的?从DELETE TABLE1 WHERE NOT EXISTS(SELECT * FROM TABLE2 WHERE TABLE1.ID = TABLE2.TABLE1_ID)AND NOT EXISTS(SELECT * FROM TABLE3 WHERE TABLE1.ID = TABLE3.TABLE1_ID)'它比我原来的语句好得多。 – res1

+0

事实上,只有我会在子查询中进一步使用'top 1 1'而不是'*'。 – Blindy

+1

似乎是Apache的德比不支持top – res1

0
DELETE from table1 
WHERE 
    table1_id NOT IN (SELECT table1_id FROM table2) 
    AND 
    table1_id NOT IN (SELECT table1_id FROM table3) 
+1

我认为你的意思不在? – HLGEM

+0

你的意思是'AND'而不是'OR'? table1_id NOT IN(SELECT table1_id FROM table2) AND table1_id NOT IN(SELECT table1_id FROM table3) –

+0

@Hugh - 谢谢 - 修正了它。 – Chains

1
DELETE  table1 
FROM  table1 
LEFT JOIN table2 ON table1.id = table2.table1_id 
LEFT JOIN table3 ON table1.id = table3.table1_id 
WHERE table2.table1_id IS NULL 
    AND table3.table1_id IS NULL 
0

你知不知道你有多少行删除?我同意@布林迪,如果德比支持它,那么不存在的话可能会更好(我不知道德比,所以我不能肯定地说)。但是,如果有很多记录被删除,您可能需要批量执行此操作。无论查询有多高效,删除10,000,000条记录都需要很长时间。在循环中一次删除1000个数据库通常对数据库更好,因为在整个过程完成时,它不会占用表锁并锁定用户。我再次不了解德比,所以我不知道德比是否属实,但它肯定会帮助我熟悉的大多数数据库中的大量删除。