首页 > 解决方案 > 如何在不更改查询的情况下改进此 oracle 11g 计划选择?

问题描述

我有一组 oracle 11g 数据库表的数据重新填充方案,它需要:

在重新加载过程之后,我运行了一些报告,并且我有一个问题查询类,当它可以/应该是亚秒级时需要 7 秒。我已经对查询进行了改进,例如使用参数并在 where 子句中更具体。带着这个问题,我不是试图改进查询,而是试图改进引擎选择的计划,或者至少了解它的神秘行为。

查询是从列表达式列表(未分组的、聚合的)生成的,其中我chunk将列表分为若干列(例如 3、4、5),以查看报告中的最佳视觉效果。对于给定的一组连接子句,选择的列表达式的数量和其他一些因素(一天中的时间、缓存、温度,谁知道)影响优化器是选择快速计划还是慢速计划。

这是具有 1 个分组列multiplier和 5 个非分组聚合表达式的示例查询:

SELECT
    TO_.multiplier
    -- multiplier.bracket
    ,   min(TCA.TCA_SECURITY.symbol)
    -- symbol.min
    ,   min(TO_.px_limit)
    -- px_limit.min
    ,   min(TCA.TCA_SECURITY_DAY_BAR.px_open_day)
    -- px_open_day.min
    ,   min(TCA.TCA_SECURITY_DAY_BAR.px_high_day)
    -- px_high_day.min
    ,   min(TCA.TCA_SECURITY_DAY_BAR.px_low_day)
    -- px_low_day.min
FROM TCA_ORDER TO_
    LEFT JOIN TCA_ORDER_SECURITY ON (TO_.ID = TCA_ORDER_SECURITY.ORDER_ID)
    LEFT JOIN TCA.TCA_SECURITY TCA_SECURITY ON (TCA_ORDER_SECURITY.SECURITY_ID = TCA_SECURITY.ID)
    LEFT JOIN TCA.TCA_SECURITY_DAY_BAR ON (
        TCA_SECURITY.ID = TCA_SECURITY_DAY_BAR.SECURITY_ID
        AND TO_.TRADE_DATE = TCA_SECURITY_DAY_BAR.TRADE_DATE
    )

WHERE TRADING_UNIT_ID IN (621)
GROUP BY TO_.multiplier

观察:

我知道架构设置为每晚运行统计信息,但我真的不知道用于此的确切命令。如果那些夜间统计数据收集电话不是特别的,我可以自己按需调用它们,这可能会有所帮助——我只需要知道如何准确地模仿它。

为了尝试排除故障,在我的 kotlin/jdbc 代码中,我使用了解释上次计划运行的调用。这是一个 diff,显示了一个 5 列快速和 4 列慢的查询。很明显,由于某种原因,它在慢速情况下选择了“NESTED LOOPS OUTER”,我不知道为什么。

因此,我正在寻找对可能发生的事情的解释以及在不更改查询的情况下影响优化器选择的建议。

通过添加列来快速区分样本

标签: sqloracleoptimizationjdbcsql-execution-plan

解决方案


  1. 如果您要在
    删除/重新创建/填充后触发相同的查询并且您的数据不会发生很大变化,您可以使用 SQL 计划基线。基本上建立一个好的计划并在执行相同的查询时强制oracle使用它。您可以在这里找到更多信息: https ://docs.oracle.com/database/121/TGSQL/tgsql_spm.htm#TGSQL94621
  2. 如果选项 1) 不适合您,您还可以启用动态采样。如果尚未收集统计信息,这将基本上在运行时为一小部分行收集统计信息。:https ://oracle-base.com/articles/12c/dynamic-statistics-12cr1

此外,为了快速收集表格的统计信息,您可以将“estimate_percent”设置为较小的数字(5-10%),这将快速收集统计信息,但可能会与自动收集统计信息发生冲突。


推荐阅读