【问题标题】:Optimizing Oracle CONNECT BY when used with WHERE clause与 WHERE 子句一起使用时优化 Oracle CONNECT BY
【发布时间】:2010-11-08 01:40:15
【问题描述】:

Oracle START WITH ... CONNECT BY 子句在之前在同一查询中应用WHERE 条件。因此,WHERE 约束无助于优化CONNECT BY

例如,以下查询可能会执行全表扫描(忽略dept_id 的选择性):

SELECT * FROM employees 
WHERE dept_id = 'SALE'
START WITH manager_id is null
CONNECT BY PRIOR employee_id = manager_id

我尝试通过两种方式提高性能:

查询 A:

SELECT * FROM employees 
START WITH manager_id is null AND dept_id = 'SALE'
CONNECT BY PRIOR employee_id = manager_id

查询 B:

SELECT * FROM (
               SELECT * FROM employees 
                WHERE dept_id = 'SALE'
              )
START WITH manager_id is null
CONNECT BY PRIOR employee_id = manager_id

虽然这两个查询的性能都比原始查询好得多,但在 Oracle 10g 第 2 版中,查询 B 的性能确实比 A 好得多。

您是否针对CONNECT BYWHERE 子句进行了类似的性能优化?你如何解释查询 B 比查询 A 做得更好?

【问题讨论】:

  • 显示解释计划,甚至可能是跟踪文件,你有什么样的索引?无论如何,我认为您自己已经解释了为什么 B 更快,B 更快是因为首先评估了 where。
  • null 值没有放在索引中,因此也许您可以将 null 的含义替换为 0 或 -1 或类似的值以允许索引工作。
  • @tuinstoel - 是的,看起来减少 CONNECT BY 操作的数据集比减少 START WITH 的初始集更好。我更多地考虑各种优化方法:我尝试在 CONNECT BY 中使用约束,但这没有成功。
  • 你更新数据了吗?使用直方图统计

标签: sql performance oracle select query-optimization


【解决方案1】:

这是一个类似的查询,长话短说,使用嵌套 sql 比通过先前选项进行双重连接更快。

'SELECT level, XMLElement("elemento", XMLAttributes(codigo_funcion as "Codigo",
                                                    nombre_funcion as "Nombre",
                                                    objetivos as "Objetivos",
                                                     descripcion as "Descripción",
                                                    ''rightHanging'' as "layout"))
   FROM (
           SELECT * FROM dithe_codigo_funcion 
           WHERE nodo_raiz = ''PEP''
    )      
   START WITH codigo_funcion = ''PEP'' 
   CONNECT BY PRIOR codigo_funcion = nivel_anterior'; 

所以我没有太多专业知识的建议是使用嵌套sql进行过滤。

【讨论】:

    【解决方案2】:

    这应该会提供终极性能:

    CREATE INDEX i_employees_employee_manager_dept ON employees (employee_id,manager_id,dept_id);
    CREATE INDEX i_employees_manager_employee_dept ON employees (manager_id,employee_id,dept_id);
    
    SELECT * FROM employees  
    START WITH manager_id is null AND dept_id = 'SALE' 
    CONNECT BY PRIOR employee_id = manager_id AND dept_id = 'SALE' 
    

    请注意,您确实需要 index 和 AND 两个条件才能进行优化。

    【讨论】:

    • 我们可以将其重写为from employees join dual on dept_id = 'SALE' 以避免重复此过滤器两​​次吗?
    【解决方案3】:

    查询 A 说从销售部门的经理开始,然后让他们的所有员工。 Oracle 不“知道”查询返回的所有员工将在销售部门,因此它不能使用该信息来减少在执行 CONNECT 之前要使用的数据集经过。

    查询 B 显式将要处理的数据集减少到仅针对 Sales 中的那些员工,然后 Oracle 可以在执行 CONNECT BY 之前执行此操作。

    【讨论】:

    • 请注意,这个答案只解释了为什么 B 比 A 好,但是 @jluu 提供的解决方案 C 对我来说做得更好
    • A 比原来更快的答案在于 Oracle 按以下顺序评估子句:FROM(包括 JOIN)、CONNECT BY(包括 START WITH)、WHERE、GROUP BY、拥有、选择、订购方式
    【解决方案4】:

    员工的索引是什么?你最好有一个关于employeeid的索引。由于将employeeid 声明为主键,您可能确实有一个。

    使用 managerid 上的索引可能会获得更好的性能。试试吧。在插入新员工或重组管理关系时,这必须与性能下降相平衡。

    【讨论】:

    • Walter,所有索引都在那里。谢谢。
    猜你喜欢
    • 1970-01-01
    • 2012-04-20
    • 1970-01-01
    • 2016-05-06
    • 1970-01-01
    • 1970-01-01
    • 2015-07-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多