【问题标题】:Optimizing Oracle stored procedures优化 Oracle 存储过程
【发布时间】:2012-02-26 02:28:53
【问题描述】:

我最近的任务是优化一些现有的 Oracle 存储过程。每个存储过程都会查询数据库并生成 XML 文件输出。一个特别是需要大约 20 分钟才能完成执行。看看它有几个嵌套循环和不必要的查询。例如,而不是做一个

SELECT * from Employee e, Department d WHERE e.DEPT_ID = d.ID
--write data from query to XML

更像是

FOR emp_rec in ( SELECT * from employee )
LOOP
   SELECT * from Department WHERE id = emp_rec.DEPT_ID;
   --write data from query to XML
END LOOP;

将所有这些案例更改为更像第一个选项,极大地加快了程序的速度。我的问题是为什么?为什么在选择查询中进行连接比手动组合表更快?底层流程是什么?

【问题讨论】:

    标签: sql oracle stored-procedures


    【解决方案1】:

    “基础流程”需要一个重要的答案。我会留下Tom Kyte 来回答这个问题;)

    【讨论】:

      【解决方案2】:

      让我们看看原始版本可能会如何处理。

      FOR emp_rec in ( SELECT * from employee )
      LOOP
         SELECT * from Department WHERE id = emp_rec.DEPT_ID;
         --write data from query to XML
      END LOOP;
      

      循环查询很可能对employee 进行全表扫描。然后,对于返回的每一行,它将执行内部查询。假设iddepartment的主键,那么每次执行查询都可能使用主键索引进行唯一查找。

      听起来不错,对吧?唯一索引查找通常是获得单行的最快方法(通过 ROWID 显式查找除外)。但是想想这在循环的多次迭代中做了什么。想必每个员工都属于一个部门;每个部门都有员工;大多数或所有部门都有多名员工。

      因此,在循环的多次迭代中,您会多次为内部查询重复完全相同的工作。是的,数据块可能会被缓存,因此您不必重复物理读取,但访问缓存中的数据确实有一些 CPU 开销,当反复访问相同的块时,这会变得非常重要。

      此外,最终您可能希望department 中的每一行至少一次,并且可能不止一次。由于需要读取表中的每个块,因此执行索引查找并没有真正节省工作 - 您正在添加工作。

      当您将循环重写为单个查询时,优化器能够考虑到这一点。一种选择是执行由employee 驱动的嵌套循环连接,这与PL/SQL 中的显式循环基本相同(减去Mark 指出的上下文切换)。然而,考虑到两个表之间的关系,并且没有任何过滤谓词,优化器将能够判断出简单地全扫描两个表并进行合并或散列连接会更有效。这实际上会导致更少的物理 IO(假设每次执行开始时都有干净的缓存)和更少的逻辑 IO。

      【讨论】:

      • 很好的回复。还有一个比我提供的更好的答案... :-)
      猜你喜欢
      • 2021-04-17
      • 2018-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多