【问题标题】:Oracle SQL: additional restriction causes performance issuesOracle SQL:附加限制导致性能问题
【发布时间】:2013-11-08 10:19:54
【问题描述】:

我在使用 oracle SQL 语句时遇到了一个奇怪的性能问题。该语句或多或少是一个巨大的子选择/内部连接语句,因此我只能在这里发布它的结构。它看起来像这样:

SELECT "A".COL1, [...] FROM "A"
INNER JOIN ( .. massive amount of subselects and joins ... )
WHERE [...]

该语句的执行速度非常快(约 30 秒)。为了进一步提高速度,我决定按时间限制选择:

SELECT "A".COL1, [...] FROM "A"
INNER JOIN ( .. massive amount of subselects and joins ... )
WHERE "A".TIMESTAMP > ... AND [...]

这产生了完全相反的效果。语句执行时间现在超过 600 秒 (!!)。

现在解释计划的设置完全不同(正如我所说,仅仅因为一个 MORE 限制 - 该限制有一个完整的索引)。之前它是具有连接、索引限制和快速全扫描的“正常”组合。之后,它被成千上万个嵌套循环完全搞砸了。

我知道这很难从外部判断,但是有什么一般提示会导致这些嵌套循环在开始时出现吗? EXPLAIN 计划开始 (!!) 之前:“正常”组合的哈希连接限制等等。深度总是


| Id  | Operation                                             | Name               | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                                      |                    |   461 |   286K|  1672   (5)| 00:00:11 |
|   1 |  SORT GROUP BY                                        |                    |   461 |   286K|  1672   (5)| 00:00:11 |
|*  2 |   HASH JOIN                                           |                    |   461 |   286K|  1671   (5)| 00:00:11 |
|   3 |    VIEW                                               | index$_join$_016   |  2822 | 93126 |    21   (5)| 00:00:01 |
|*  4 |     HASH JOIN                                         |                    |       |       |            |          |
|*  5 |      INDEX RANGE SCAN                                 | HRP1000~0          |  2822 | 93126 |     5   (0)| 00:00:01 |
|*  6 |      INDEX FAST FULL SCAN                             | HRP1000~1          |  2822 | 93126 |    19   (0)| 00:00:01 |
|*  7 |    HASH JOIN                                          |                    |   459 |   270K|  1649   (5)| 00:00:11 |
|*  8 |     HASH JOIN                                         |                    |   459 |   259K|  1609   (5)| 00:00:10 |
|*  9 |      TABLE ACCESS FULL                                | BBP_PDORG          | 14463 |   607K|    39   (0)| 00:00:01 |
|* 10 |      HASH JOIN                                        |                    |  1939 |  1013K|  1569   (5)| 00:00:10 |
|* 11 |       HASH JOIN RIGHT OUTER                           |                    |   691 |   335K|  1548   (5)| 00:00:10 |
|  12 |        VIEW                                           |                    |  1572 | 47160 |   148   (5)| 00:00:01 |
|  13 |         HASH GROUP BY                                 |                    |  1572 |   411K|   147   (5)| 00:00:01 |

After - 大量嵌套循环。深度 > 20


| Id  | Operation                                                    | Name               | Rows  | Bytes | Cost (%CPU)| Time
----------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                                             |                    |     1 |  1392 |   329   (6)| 00:00:03
|   1 |  SORT GROUP BY                                               |                    |     1 |  1392 |   328   (5)| 00:00:03
|   2 |   NESTED LOOPS                                               |                    |     1 |  1392 |   327   (5)| 00:00:03
|   3 |    NESTED LOOPS                                              |                    |     1 |  1371 |   327   (5)| 00:00:03
|   4 |     NESTED LOOPS                                             |                    |     1 |  1333 |   327   (5)| 00:00:03
|   5 |      NESTED LOOPS                                            |                    |     1 |  1312 |   327   (5)| 00:00:03
|   6 |       NESTED LOOPS                                           |                    |     1 |  1274 |   326   (5)| 00:00:03
|   7 |        NESTED LOOPS                                          |                    |     1 |  1235 |   326   (5)| 00:00:03
|   8 |         NESTED LOOPS                                         |                    |     1 |  1196 |   326   (5)| 00:00:03
|   9 |          NESTED LOOPS                                        |                    |     1 |  1175 |   326   (5)| 00:00:03
|  10 |           NESTED LOOPS                                       |                    |     1 |  1137 |   325   (5)| 00:00:03
|  11 |            NESTED LOOPS                                      |                    |     1 |  1116 |   325   (5)| 00:00:03
|  12 |             NESTED LOOPS                                     |                    |     1 |  1078 |   325   (5)| 00:00:03
|  13 |              NESTED LOOPS                                    |                    |     1 |  1061 |   325   (5)| 00:00:03
|  14 |               NESTED LOOPS                                   |                    |     1 |  1010 |   324   (5)| 00:00:03
|  15 |                NESTED LOOPS                                  |                    |     1 |   988 |   324   (5)| 00:00:03
|* 16 |                 HASH JOIN                                    |                    |     1 |   953 |   324   (5)| 00:00:03
|  17 |                  NESTED LOOPS                                |                    |       |       |            |
|  18 |                   NESTED LOOPS                               |                    |     1 |   898 |   284   (6)| 00:00:02
|  19 |                    NESTED LOOPS                              |                    |     1 |   853 |   284   (6)| 00:00:02
|* 20 |                     HASH JOIN                                |                    |     1 |   823 |   284   (6)| 00:00:02
|  21 |                      NESTED LOOPS                            |                    |     1 |   780 |   236   (6)| 00:00:02
|  22 |                       NESTED LOOPS                           |                    |     1 |   741 |   236   (6)| 00:00:02
|  23 |                        NESTED LOOPS                          |                    |     1 |   701 |   235   (6)| 00:00:02
|  24 |                         NESTED LOOPS                         |                    |     1 |   639 |   235   (6)| 00:00:02
|  25 |                          NESTED LOOPS                        |                    |     1 |   609 |   235   (6)| 00:00:02
|  26 |                           NESTED LOOPS                       |                    |     1 |   576 |   235   (6)| 00:00:02
|  27 |                            NESTED LOOPS                      |                    |     1 |   533 |   234   (6)| 00:00:02
|  28 |                             NESTED LOOPS                     |                    |     1 |   495 |   234   (6)| 00:00:02

【问题讨论】:

  • index 有时可以做到这一点......你试过收集统计数据吗?

标签: sql performance oracle explain sql-execution-plan


【解决方案1】:

以下可能是时间增加的原因:-

  1. INDEX:- 如果假设您之前的查询的 where 条件是(其中 col1 ='' 和 col2 = '')并且您已经在 col1 ,col2 上创建了一个复合索引,那么您的查询将使用该索引并执行索引快速全扫描等。如果您的时间戳过滤器未编入索引,则您的查询不再使用索引,而是进行全表扫描(增加时间)

  2. 时间戳列放置:- 由于时间戳放置错误,您的解释计划的深度会增加。正如我们所知,我们的查询从最后开始运行,即假设您的查询的 where 条件是这样的(其中 col1 = '' and col2 = '' and col3 = '')所以您的数据将首先根据 col3 然后 col2 然后科尔1。因此,如果在您的子查询中添加了此时间戳条件。每次您的查询都会根据时间戳进行过滤,因为我们知道每次处理外部查询时都会运行子查询。

所以我建议如果您在子查询中使用时间戳然后修改相同。 建议:- 分析查询或派生查询比子查询运行得更快,因为子查询的限制是,对于外部查询的每一行,内部查询都会被处理

【讨论】:

    【解决方案2】:

    优化器可能认为A.TIMESTAMP > ... 会大大减少命中次数,因此对少量行使用嵌套循环比执行大型连接更便宜。

    根据所提供的稀缺信息,很难确定确切的原因以及是否有简单的方法来纠正问题。

    当您添加索引(或索引列上的条件)时,执行计划会发生巨大变化,您应该不会感到惊讶。 我有点惊讶它选择更改> 比较的计划。限制是固定值(即优化器是否知道),是否接近表中的最大值(如表统计信息中记录的那样)?

    关于时间戳有一个警告,即最高值的统计数据很快就会过时。 假设您的统计数据是 24 小时前的,并且您正在查找过去 24 小时内的日期。优化器将使用统计信息并预测查询将导致 0 次命中。所以它将从检查索引开始。

    实际上,您在过去 24 小时内输入了许多新记录。一整天的新记录...

    直接设置优化器的一种方法是提供截止日期作为参数(并在适用的情况下预编译问题),这样优化器就不会误以为它会获得 0 次点击。

    【讨论】:

    • 好吧,你是对的。如果我使用一个非常旧的时间戳(2 年),它会“工作”(使用哈希连接)。在我尝试使用一个月之前(它是一个SAP质量系统,所以当时没有太多新条目)。 “直接设置优化器的一种方法是提供截止日期作为参数,这样优化器就不会被愚弄认为它会获得 0 次点击。”你是什么意思?通过 SAP,我只能直接执行“本机 SQL”(意味着:无法轻松访问预编译/存储过程等)。我怎样才能给参数“截止”日期作为参数?
    • 带参数我的意思是绑定变量。在 SQL Developer 中,您使用 :varname 来使用绑定变量。在 JDBC 中,您使用 ?
    • 不确定 - 正如我所说的,我只能通过 ABAP 直接访问 - SQL Developer(和类似工具)不在我的手中......很好的旧任务分离。因此,我也不需要“绑定变量”——因为 SQL 语句是动态生成的。我只需要知道如何告诉 Oracle 结果比它想象的要大(最好的情况,直接通过 SQL 语句中的 SQL 提示)。还是我必须在这里通知我的技术基础团队,它应该“优化”优化器统计值?
    • 我猜你可以暗示不要使用索引:/*+NO_INDEX("A" index_name)*/.
    猜你喜欢
    • 2015-02-16
    • 2013-01-07
    • 1970-01-01
    • 2021-08-09
    • 2019-05-04
    • 2013-04-01
    • 1970-01-01
    • 2017-12-10
    • 2012-02-10
    相关资源
    最近更新 更多