【发布时间】: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