SQL优化:删除需要很长时间

SQL优化:删除需要很长时间,sql,oracle,optimization,stored-procedures,plsql,Sql,Oracle,Optimization,Stored Procedures,Plsql,我将Oracle SQL查询作为存储过程的一部分: DELETE FROM item i WHERE NOT EXISTS (SELECT 1 FROM item_queue q WHERE q.n=i.n) AND NOT EXISTS (SELECT 1 FROM tool_queue t WHERE t.n=i.n); 关于表格: 该项包含大约10k行,在n列上有一个索引 item_队列包含大约1mil行,索引也位于n列上 tool_队列也包含大约5 mil个索引行 我想知道

我将Oracle SQL查询作为存储过程的一部分:

DELETE FROM item i 
 WHERE NOT EXISTS (SELECT 1 FROM item_queue q WHERE q.n=i.n) 
 AND NOT EXISTS (SELECT 1 FROM tool_queue t WHERE t.n=i.n);
关于表格:

  • 该项包含大约10k行,在n列上有一个索引
  • item_队列包含大约1mil行,索引也位于n列上
  • tool_队列也包含大约5 mil个索引行

我想知道是否可以以某种方式优化查询/子查询以使其运行得更快,我认为删除通常相当快

尝试使用SELECT而不是delete来查看删除操作是否是真正的瓶颈

将您的删除转换为SELECT,然后您可以检查并优化查询部分

否则,注意删除并不是最快的事情。删除时会发生很多事情


奥托,我真的认为。。。。问题在于这两个子查询。查询计划是什么样子的?

尝试在您的要求中避免子选择,而改用内部联接

虽然它可能不会更快,但如果您这样做,阅读起来会更容易:

DELETE FROM item i 
WHERE n NOT IN (SELECT n FROM item_queue)
AND n NOT IN (SELECT n FROM tool_queue)
尝试以下方法:

 DELETE FROM item WHERE n NOT IN 
     (SELECT i.n FROM item i INNER JOIN item_queue q ON i.n = q.n
      UNION SELECT i.n FROM item i INNER JOIN tool_queue t ON i.n = t.n)
在您的示例中,每个相关子查询都运行了10K次。此技术将运行两个内部联接查询以获取要删除的“n”的列表


您可能需要稍微修改一下SQL;我不熟悉Oracle方言。

请确保对引用项目表的大型表没有约束。在删除的情况下,这可能是一个真正的减速。

如果不做额外的工作,你就不可能真正得到一个好的答案

在SQL语句iteself之后,最重要的是对象(本例中为表和索引)的统计数据具有代表性

然后,您真的需要看看oracle选择的访问路径——有很多方法可以做到这一点

试一试

然后

也许把结果贴在这里

当您尝试不同的事情时,例如重新编写查询、修改索引等,您会注意到访问路径发生了变化

这是一个相当复杂的领域,你需要学习/实践

删除速度慢的原因有很多,但一个重要因素是表上索引的维护。然而,在你的例子中,你说只有10k行,这是相当小的。(顺便说一句,你没有给出时间。目前需要1、10或100秒吗?你想实现什么?)因此我将重点关注通过较大表的访问路径

我的第一个方法可能是:

DELETE FROM item i 
 WHERE NOT EXISTS 
(SELECT NULL
 FROM item_queue q,
      tool_queue g
  where q.key = g.key      -- if the tables are related
    AND q.n=i.n) ;

但正如我所说,这里有很多因素。

请重新格式化代码,使其不在滚动窗格中。除非内部联接不起作用。如果您在
项_队列
工具_队列
之间进行内部联接,您将得到不想删除的
的子集。内部联接不是比select语句更昂贵吗?如果我错了,请纠正我。@Shannon Severance黄金法则“两次选择一次删除”@sprasad12让有更多经验的人纠正我,但我知道,子选择和函数的速度要慢得多,然后在适当的约束条件下加入查询优化器将为您更改它。如果没有它们,它可能是等效的,也可能不是等效的。对于Oracle来说,语法应该很好,但我认为您需要使用
而不是
,因为最初的检查表明两者都不存在。另外,使用excplicit联接将使其更具可读性。谢谢你,彼得,你是对的。我编辑了答案,将两个查询分开,并将结果集合并在一起,从而避免了陷入混乱的多表联接;我重新格式化使用内部联接语法(虽然对于像我这样的老家伙来说,它们同样可读)。@Larry Lustig:我同意在这种情况下它们同样可读,但我怀疑有人可能已经足够大了,可以找到使用数十个隐式联接表和一些实际条件混合的查询,它们同样可读;-)我不知道,彼得。我很老了。取决于你习惯了什么。。。我看不懂什么!T我想在一个地方看到所有的桌子。没有分散。真正的问题是设计问题。他们把工具和物品分开的事实可能是一个错误。如果需要,它可能应该是一个带有区分列的单队列表。我打赌他们到处都有这样的代码。。。
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
DELETE FROM item i 
 WHERE NOT EXISTS 
(SELECT NULL
 FROM item_queue q,
      tool_queue g
  where q.key = g.key      -- if the tables are related
    AND q.n=i.n) ;