【问题标题】:Providing Partition Key to partitioned table, increases query cost为分区表提供分区键,增加查询成本
【发布时间】:2019-06-12 23:48:59
【问题描述】:

我正在开发一个查询包含大量数据的表的 Web 应用程序。由于 UI 性能问题 - 我一直在研究提高长时间运行查询性能的方法。

请参阅下面的原始代码示例和解释计划。

 EXPLAIN PLAN FOR
SELECT * FROM T1
INNER JOIN T2 ON (T2.ID = T1.ID)
WHERE
        T1.EMPLOYEE_ID = '1001'
        AND T1.RUN_TIMESTAMP = '16-JAN-19 17.39.36.000000000'

-----------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                            | Name                         | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                     |                              | 37183 |    31M|       | 37654   (1)| 00:00:02 |
|*  1 |  HASH JOIN                           |                              | 37183 |    31M|  6688K| 37654   (1)| 00:00:02 |
|*  2 |   TABLE ACCESS BY INDEX ROWID BATCHED| T1                           | 37183 |  6245K|       |  2492   (1)| 00:00:01 |
|*  3 |    INDEX RANGE SCAN                  | IDX_T1_RT                    | 76305 |       |       |   410   (1)| 00:00:01 |
|   4 |   TABLE ACCESS FULL                  | T2                           |   577K|   399M|       | 14704   (1)| 00:00:01 |
-----------------------------------------------------------------------------------------------------------------------------

分区表

为了提高查询性能 - 我决定按值对大表 T1 进行分区。创建了 45 个分区,覆盖了表中每个条目分配的 45 个不同的值。出于本示例的目的 - 值 1-45。

在将数据从 T1 迁移到分区表 T1_PART 并提供不同的分区键后 - 我很失望地看到,尽管现在只按预期扫描单个分区。成本收益只是微不足道的。

EXPLAIN PLAN FOR
SELECT * FROM T1_PART
INNER JOIN T2 ON (T2.ID = T1.ID)
WHERE
        T1.EMPLOYEE_ID = '1001'
        AND T1.PARTITION_KEY = '1'
        AND T1.RUN_TIMESTAMP = '16-JAN-19 17.39.36.000000000'

----------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                                   | Name                         | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     | Pstart| Pstop |
----------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                            |                              | 19912 |    17M|       | 37341   (1)| 00:00:02 |       |       |
|*  1 |  HASH JOIN                                  |                              | 19912 |    17M|  3680K| 37341   (1)| 00:00:02 |       |       |
|   2 |   PARTITION LIST SINGLE                     |                              | 19912 |  3441K|       |  2131   (1)| 00:00:01 |   KEY |   KEY |
|*  3 |    TABLE ACCESS BY LOCAL INDEX ROWID BATCHED| T1_PART                      | 19912 |  3441K|       |  2131   (1)| 00:00:01 |    19 |    19 |
|*  4 |     INDEX RANGE SCAN                        | IDX_T1_RT                    | 57355 |       |       |   276   (1)| 00:00:01 |    19 |    19 |
|   5 |   TABLE ACCESS FULL                         | T2                           |   577K|   403M|       | 14706   (1)| 00:00:01 |       |       |
----------------------------------------------------------------------------------------------------------------------------------------------------

但是,我真正感兴趣的是,当我不再指定分区键时,查询的成本会大大降低。

从计划中我们可以看出,我们现在对表执行全面扫描,但现在使用某种我没有预料到的并行化形式来执行。

EXPLAIN PLAN FOR
SELECT * FROM T1_PART
INNER JOIN T2 ON (T2.ID = T1.ID)
WHERE
        T1.EMPLOYEE_ID = '1001'
        AND T1.RUN_TIMESTAMP = '16-JAN-19 17.39.36.000000000'

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                                        | Name                         | Rows  | Bytes | Cost (%CPU)| Time     | Pstart| Pstop |    TQ  |IN-OUT| PQ Distrib |
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                                 |                              | 19912 |    17M| 16926   (1)| 00:00:01 |       |       |        |      |            |
|   1 |  PX COORDINATOR                                  |                              |       |       |            |          |       |       |        |      |            |
|   2 |   PX SEND QC (RANDOM)                            | :TQ10002                     | 19912 |    17M| 16926   (1)| 00:00:01 |       |       |  Q1,02 | P->S | QC (RAND)  |
|*  3 |    HASH JOIN BUFFERED                            |                              | 19912 |    17M| 16926   (1)| 00:00:01 |       |       |  Q1,02 | PCWP |            |
|   4 |     PX RECEIVE                                   |                              | 19912 |  3519K|  2217   (1)| 00:00:01 |       |       |  Q1,02 | PCWP |            |
|   5 |      PX SEND HYBRID HASH                         | :TQ10000                     | 19912 |  3519K|  2217   (1)| 00:00:01 |       |       |  Q1,00 | P->P | HYBRID HASH|
|   6 |       STATISTICS COLLECTOR                       |                              |       |       |            |          |       |       |  Q1,00 | PCWC |            |
|   7 |        PX PARTITION LIST ALL                     |                              | 19912 |  3519K|  2217   (1)| 00:00:01 |     1 |    45 |  Q1,00 | PCWC |            |
|*  8 |         TABLE ACCESS BY LOCAL INDEX ROWID BATCHED| T1_PART                      | 19912 |  3519K|  2217   (1)| 00:00:01 |     1 |    45 |  Q1,00 | PCWP |            |
|*  9 |          INDEX RANGE SCAN                        | IDX_T1_RT                    | 57355 |       |   383   (1)| 00:00:01 |     1 |    45 |  Q1,00 | PCWP |            |
|  10 |     PX RECEIVE                                   |                              |   577K|   403M| 14706   (1)| 00:00:01 |       |       |  Q1,02 | PCWP |            |
|  11 |      PX SEND HYBRID HASH                         | :TQ10001                     |   577K|   403M| 14706   (1)| 00:00:01 |       |       |  Q1,01 | S->P | HYBRID HASH|
|  12 |       PX SELECTOR                                |                              |       |       |            |          |       |       |  Q1,01 | SCWC |            |
|  13 |        TABLE ACCESS FULL                         | T2                           |   577K|   403M| 14706   (1)| 00:00:01 |       |       |  Q1,01 | SCWP |            |
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

有人知道这里会发生什么吗?有没有办法在并行执行 SQL 时仅利用单个分区扫描?

感谢您的帮助! 比利

编辑:

在这个例子中...

T1 有 625,417 行

T2 有 577,718 行

T1 中的所有行都匹配 T2 上的连接条件

T1 中的 57,355 行匹配 T1.EMPLOYEE_ID = '1001' AND T1.RUN_TIMESTAMP = '16-JAN-19 17.39.36.000000000

T2 在 ID 上具有唯一索引且未分区

【问题讨论】:

  • 我有三个与第一个查询相关的问题:1)您从T2 读取了多少行? 2) T2 是否有类似T2 (ID) 的索引? 3)T1中有多少行符合条件T1.EMPLOYEE_ID = '1001' AND T1.RUN_TIMESTAMP = '16-JAN-19 17.39.36.000000000'
  • 嗨 - 我已经更新了帖子来回答这些问题。谢谢!
  • 您是否将时间戳存储为 VARHCHAR2?为什么?
  • 你为什么引用1001这样的号码?
  • 抛开成本,实际性能对比如何?我个人很少看成本栏。

标签: sql database oracle performance partition


【解决方案1】:

我有一种情况,我加入了两个表,两个表都被分区了。该查询在第一个表上使用了索引,但对第二个表执行了全表扫描。我添加了使用第二个表上的索引的提示。有了这个提示,解释计划显示了使用第二个表上的索引的查询。
如果您在 T2.ID 上有索引,我建议您在查询中为该索引添加提示。

【讨论】:

    猜你喜欢
    • 2016-04-13
    • 2016-08-05
    • 1970-01-01
    • 1970-01-01
    • 2012-08-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-02
    • 2015-02-01
    相关资源
    最近更新 更多