sql - 如何在不更改查询的情况下改进此 oracle 11g 计划选择?

标签 sql oracle optimization jdbc sql-execution-plan

我有一个针对一组 Oracle 11g 数据库表的数据重新填充方案,需要:

  • 删除并重新创建所有表。删除就像DROP TABLE TCA_SECURITY_DAY_BAR CASCADE CONSTRAINTS PURGE
  • 加载静态数据 - 即查找表,然后加载一些与日期相关的数据
  • 在加载过程中的不同时间,我散布收集统计信息命令,我发现这些命令极大地加快了加载过程本身的各种查询。然而,我对自己的选择缺乏信心,因为它们是通过猜测选择的。

    • 目标表收集调用。示例:

    dbms_stats.gather_table_stats(                            
        ownname => 'TCA',                                     
        tabname => 'TCA_SECURITY_DAY_BAR',               
        estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE,      
        block_sample => TRUE,                                 
        method_opt => 'FOR ALL INDEXED COLUMNS SIZE 1',       
        cascade => TRUE                                       
    );                                                        
    
    • 架构调用:示例:

    dbms_stats.gather_schema_stats(
        ownname => 'TCA',
        estimate_percent => NULL,
        block_sample => TRUE,
        method_opt => 'FOR ALL INDEXED COLUMNS SIZE 1',
        cascade => TRUE,
        granularity => 'ALL',
        options => 'GATHER'                                                                                                                     
    )                                                                                                                                      
    

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

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

以下是包含 1 个分组列乘数 和 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

观察结果:

  • 在比较具有不同列数的查询时,我没有运行中间的统计信息,并且我相信它们没有运行(因为设置是每晚执行一次)。
  • 一旦形成慢速查询模式,它就会在一段时间内保持一致。
  • 最初,我发现 5 列的查询总是很慢(> 7 秒)
  • 如果我只有 4 个,那就很快了。
  • 第二天5号突然就快了。但选择 4 列的速度很慢。
  • 当我将记录的运行缓慢的查询复制/粘贴到 SQL Developer 中时,它们的速度很快
  • 截至今天早上 - 3 是快,4 是慢,5 是快

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

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

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

Sample Diff-Faster By Adding Column

最佳答案

  1. 如果您要在之后触发相同的查询
    删除/重新创建/填充并且您的数据不会发生很大变化,您可以 您的 SQL 计划基线。基本上建立一个好的计划并强制甲骨文 当执行相同的查询时使用它。您可以在这里找到更多内容: 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%),这将快速收集统计信息,但可能会破坏自动收集统计信息。

关于sql - 如何在不更改查询的情况下改进此 oracle 11g 计划选择?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61777355/

相关文章:

c# - 将数据从 Oracle Server 复制到 SQL Server

algorithm - 算法问题:翻转列

cocoa - 临时文本属性导致速度大幅下降

python插入mysql

sql - 查找产品的最新发货(sql subselect?)

mysql - sql如何用新的唯一值替换数千个唯一值

oracle - 如何以编程方式将查询的源表重新映射到另一个表

sql - 如何使用没有临时表的 SQL 查询为组中的每个元素添加序列号

mysql - 使用多个左连接优化 MySQL 查询

php - MySQL 选择不在另一个表中的 ID