【问题标题】:Performance of query with lower cost以更低的成本执行查询
【发布时间】:2020-04-27 06:34:40
【问题描述】:

我正在尝试优化 select 语句,但它似乎成本降低得越多,运行时间就越长。这是怎么回事?

我可以在 partition_type 上添加一个过滤器,这大大降低了查询的成本,我认为是因为对全表扫描的需求从解释计划中消失了。还有一个嵌套查询返回包含今天活动的 partition_key 的一行。保留嵌套查询会将成本增加到 20MB(全表扫描,虽然是一个小表)。用该查询的实际结果替换嵌套查询再次降低了成本。因此,如果我像这样运行查询:

  • 嵌套查询,无 partition_type:成本 20.233.522
  • 固定值,无 partition_type:成本 234.712
  • 固定值,partition_type:成本 9.611

我的问题:

  • 成本最低的查询(到目前为止)如何不比其他查询快很多,但更慢?
  • 实际分区键的嵌套查询怎么会增加这么多开销呢?我知道这是全表扫描,但它大概是 8 个字节。

在下面解释计划和查询。

查询:

SELECT CASE WHEN COUNT (*) > 0 THEN 0 ELSE 1 END AS result
FROM MYTABLE.ORDERS  O
   INNER JOIN MYTABLE.BATCH B
       ON     B.BATCH_ID = O.IN_BATCH_ID
          AND B.PARTITION_KEY = O.PARTITION_KEY
          AND B.PARTITION_TYPE = O.PARTITION_TYPE
          AND B.INSTANCE_NUMBER = O.INSTANCE_NUMBER
WHERE     O.PARTITION_KEY = (SELECT actual_partition_key
                            FROM MYTABLE.CALENDAR
                           WHERE is_active = 1) --can replace this with fixed value 123
   AND O.partition_type = 3 -- can leave this one out
   AND B.START_TIME > SYSDATE - 1 / 2 / 24
   AND B.START_TIME < SYSDATE - 10 / 60 / 24
   AND O.STATE NOT IN ('993890', '999990')
   AND O.RECEIVER IN
           (SELECT RECEIVER_ID
              FROM (  SELECT MAX (CREATION_DATE) AS CREATION_DATE,
                             RECEIVER_ID
                        FROM MYTABLE.RECEIVER_AVAILABILITY
                    GROUP BY RECEIVER_ID) MAX_CREATION_DATE
                   INNER JOIN MYTABLE.RECEIVER_AVAILABILITY
                       ON MAX_CREATION_DATE.CREATION_DATE = CREATION_DATE
             WHERE     state IN (1, 2)
                   AND creation_date < SYSDATE - 30 / 60 / 24)

最重的查询,没有 partition_type 和嵌套查询来选择当前分区: 运行时间:2 秒

    Plan
    SELECT STATEMENT  ALL_ROWSCost: 20.233.522  Bytes: 60  Cardinality: 1                                                           
           21 SORT AGGREGATE  Bytes: 60  Cardinality: 1                                                  
                 20 FILTER                                             
                        10 FILTER                                      
                               9 NESTED LOOPS  Cost: 20.233.494  Bytes: 60  Cardinality: 1                                   
                                      7 NESTED LOOPS  Cost: 20.233.494  Bytes: 60  Cardinality: 113                          
                                            4 PARTITION RANGE ITERATOR  Cost: 20.233.267  Bytes: 3.842  Cardinality: 113  Partition #: 6  Partitions determined by Key Values                  
                                                   3 PARTITION HASH ALL  Cost: 20.233.267  Bytes: 3.842  Cardinality: 113  Partition #: 7  Partitions accessed #1 - #2             
                                                          2 TABLE ACCESS FULL TABLE MYTABLE.ORDERS Cost: 20.233.267  Bytes: 3.842  Cardinality: 113  Partition #: 7  Partitions determined by Key Values      
                                                                1 TABLE ACCESS FULL TABLE MYTABLE.CALENDAR Cost: 4  Bytes: 8  Cardinality: 1  
                                            6 PARTITION RANGE ITERATOR  Cost: 1  Cardinality: 1  Partition #: 10  Partitions determined by Key Values               
                                                   5 INDEX UNIQUE SCAN INDEX (UNIQUE) MYTABLE.BATCH_PK_IDX Cost: 1  Cardinality: 1  Partition #: 10  Partitions determined by Key Values       
                                      8 TABLE ACCESS BY LOCAL INDEX ROWID TABLE MYTABLE.BATCH Cost: 2  Bytes: 26  Cardinality: 1  Partition #: 10  Partitions accessed #1                          
                        19 NESTED LOOPS SEMI  Cost: 24  Bytes: 36  Cardinality: 1                                     
                               15 VIEW myuser. Cost: 23  Bytes: 13  Cardinality: 1                                   
                                      14 FILTER                         
                                            13 SORT GROUP BY  Cost: 23  Bytes: 20  Cardinality: 1                    
                                                   12 PARTITION RANGE ALL  Cost: 22  Bytes: 6.080  Cardinality: 304  Partition #: 17  Partitions accessed #1 - #347          
                                                          11 INDEX FAST FULL SCAN INDEX MYTABLE.RECEIVER_AVAIL_IDX Cost: 22  Bytes: 6.080  Cardinality: 304  Partition #: 17  Partitions accessed #1 - #347  
                               18 PARTITION RANGE ALL  Cost: 1  Bytes: 23  Cardinality: 1  Partition #: 19  Partitions accessed #1 - #347                               
                                      17 TABLE ACCESS BY LOCAL INDEX ROWID BATCHED TABLE MYTABLE.RECEIVER_AVAILABILITY Cost: 1  Bytes: 23  Cardinality: 1  Partition #: 19  Partitions accessed #1 - #347                     
                                            16 INDEX RANGE SCAN INDEX MYTABLE.RECEIVER_AVAIL_IDX Cost: 0  Cardinality: 1  Partition #: 19  Partitions accessed #1 - #347       

用实际的 partition_key 123 替换 partition_key 的嵌套查询时: 运行时间:6 秒

Plan
SELECT STATEMENT  ALL_ROWSCost: 234.712  Bytes: 62  Cardinality: 1                                                                           
       21 SORT AGGREGATE  Bytes: 62  Cardinality: 1                                                               
             20 NESTED LOOPS SEMI  Cost: 234.712  Bytes: 62  Cardinality: 1                                                           
                    7 NESTED LOOPS  Cost: 234.688  Bytes: 60  Cardinality: 1                                                    
                           2 PARTITION RANGE ITERATOR  Cost: 234.684  Bytes: 26  Cardinality: 1  Partition #: 4  Partitions accessed #3622 - #3623                                          
                                  1 TABLE ACCESS FULL TABLE MYTABLE.BATCH Cost: 234.684  Bytes: 26  Cardinality: 1  Partition #: 4  Partitions accessed #3622 - #3623                                      
                           6 PARTITION RANGE ITERATOR  Cost: 4  Bytes: 34  Cardinality: 1  Partition #: 6  Partitions determined by Key Values                                              
                                  5 PARTITION HASH ALL  Cost: 4  Bytes: 34  Cardinality: 1  Partition #: 7  Partitions accessed #1 - #2                                        
                                        4 TABLE ACCESS BY LOCAL INDEX ROWID BATCHED TABLE MYTABLE.ORDERS Cost: 4  Bytes: 34  Cardinality: 1  Partition #: 7  Partitions determined by Key Values                           
                                               3 INDEX RANGE SCAN INDEX MYTABLE.ORDERS_IN_FILE Cost: 2  Cardinality: 1  Partition #: 7  Partitions determined by Key Values                         
                    19 VIEW PUSHED PREDICATE VIEW SYS.VW_NSO_1 Cost: 24  Bytes: 2  Cardinality: 1                                                   
                           18 NESTED LOOPS  Cost: 24  Bytes: 36  Cardinality: 1                                                 
                                  16 NESTED LOOPS  Cost: 24  Bytes: 36  Cardinality: 1                                          
                                        13 VIEW myuser. Cost: 23  Bytes: 13  Cardinality: 1                                   
                                               12 FILTER                         
                                                      11 SORT GROUP BY  Cost: 23  Bytes: 20  Cardinality: 1                      
                                                            10 FILTER           
                                                                   9 PARTITION RANGE ALL  Cost: 22  Bytes: 6.080  Cardinality: 304  Partition #: 17  Partitions accessed #1 - #347   
                                                                          8 INDEX FAST FULL SCAN INDEX MYTABLE.RECEIVER_AVAIL_IDX Cost: 22  Bytes: 6.080  Cardinality: 304  Partition #: 17  Partitions accessed #1 - #347
                                        15 PARTITION RANGE ALL  Cost: 0  Cardinality: 1  Partition #: 19  Partitions accessed #1 - #347                               
                                               14 INDEX RANGE SCAN INDEX MYTABLE.RECEIVER_AVAIL_IDX Cost: 0  Cardinality: 1  Partition #: 19  Partitions accessed #1 - #347                       
                                  17 TABLE ACCESS BY LOCAL INDEX ROWID TABLE MYTABLE.RECEIVER_AVAILABILITY Cost: 1  Bytes: 23  Cardinality: 1  Partition #: 19  Partitions accessed #1    

然后,我认为最好的查询是:包括 partition_key 和 partition_type(避免全表扫描): 运行时间:8 秒

Plan
SELECT STATEMENT  ALL_ROWSCost: 9.611  Bytes: 100  Cardinality: 1                                                                            
       22 SORT AGGREGATE  Bytes: 100  Cardinality: 1                                                                     
             21 NESTED LOOPS SEMI  Cost: 9.611  Bytes: 100  Cardinality: 1                                                            
                    8 NESTED LOOPS  Cost: 9.587  Bytes: 98  Cardinality: 1                                                      
                           3 PARTITION RANGE SINGLE  Cost: 9.587  Bytes: 26  Cardinality: 1  Partition #: 4  Partitions accessed #3622                                          
                                  2 TABLE ACCESS BY LOCAL INDEX ROWID BATCHED TABLE MYTABLE.BATCH Cost: 9.587  Bytes: 26  Cardinality: 1  Partition #: 5  Partitions accessed #3622                                   
                                        1 INDEX SKIP SCAN INDEX (UNIQUE) MYTABLE.BATCH_PK_IDX Cost: 9.586  Cardinality: 1  Partition #: 6  Partitions accessed #3622                               
                           7 PARTITION RANGE ITERATOR  Cost: 0  Bytes: 39.384  Cardinality: 547  Partition #: 7  Partitions determined by Key Values                                              
                                  6 PARTITION HASH ALL  Cost: 0  Bytes: 39.384  Cardinality: 547  Partition #: 8  Partitions accessed #1 - #2                                  
                                        5 TABLE ACCESS BY LOCAL INDEX ROWID BATCHED TABLE MYTABLE.ORDERS Cost: 0  Bytes: 39.384  Cardinality: 547  Partition #: 8  Partitions determined by Key Values                            
                                               4 INDEX RANGE SCAN INDEX MYTABLE.ORDERS_IN_FILE Cost: 0  Cardinality: 1  Partition #: 8  Partitions determined by Key Values                         
                    20 VIEW PUSHED PREDICATE VIEW SYS.VW_NSO_1 Cost: 24  Bytes: 2  Cardinality: 1                                                   
                           19 NESTED LOOPS  Cost: 24  Bytes: 36  Cardinality: 1                                                 
                                  17 NESTED LOOPS  Cost: 24  Bytes: 36  Cardinality: 1                                          
                                        14 VIEW myuser. Cost: 23  Bytes: 13  Cardinality: 1                                   
                                               13 FILTER                         
                                                      12 SORT GROUP BY  Cost: 23  Bytes: 20  Cardinality: 1                      
                                                            11 FILTER           
                                                                   10 PARTITION RANGE ALL  Cost: 22  Bytes: 6.080  Cardinality: 304  Partition #: 18  Partitions accessed #1 - #347   
                                                                          9 INDEX FAST FULL SCAN INDEX MYTABLE.RECEIVER_AVAIL_IDX Cost: 22  Bytes: 6.080  Cardinality: 304  Partition #: 18  Partitions accessed #1 - #347
                                        16 PARTITION RANGE ALL  Cost: 0  Cardinality: 1  Partition #: 20  Partitions accessed #1 - #347                               
                                               15 INDEX RANGE SCAN INDEX MYTABLE.RECEIVER_AVAIL_IDX Cost: 0  Cardinality: 1  Partition #: 20  Partitions accessed #1 - #347                       
                                  18 TABLE ACCESS BY LOCAL INDEX ROWID TABLE MYTABLE.RECEIVER_AVAILABILITY Cost: 1  Bytes: 23  Cardinality: 1  Partition #: 20  Partitions accessed #1             

【问题讨论】:

  • 您最近是否收集过表格统计信息?估计的成本可能不准确。我会尝试使用/*+ gather_plan_statistics */ 运行这些查询,以查看每个步骤的预期行数与实际行数。
  • 谢谢,这是一个很好的提示。我希望这能帮助我查明问题。
  • 我想我在调整任何东西时都没有看过cost。通常最好忽略它。

标签: sql oracle performance sql-execution-plan


【解决方案1】:

尽量去掉分区部分,因为它是最重的部分。而且我想如果你只需要检查表中是否有行,就不需要计算记录了

select result 
from
(SELECT 1 as result
   from dual
  where not exists (select 1
                      FROM MYTABLE.ORDERS  O
                      INNER JOIN MYTABLE.CALENDAR c on c.actual_partition_key = O.PARTITION_KEY
                      INNER JOIN MYTABLE.BATCH B
                         ON  B.BATCH_ID = O.IN_BATCH_ID
                         AND B.PARTITION_KEY = O.PARTITION_KEY
                         AND B.PARTITION_TYPE = O.PARTITION_TYPE
                         AND B.INSTANCE_NUMBER = O.INSTANCE_NUMBER
                       WHERE c.is_active = 1
                         AND O.partition_type = 3 -- can leave this one out
                         AND B.START_TIME > SYSDATE - 1 / 2 / 24
                         AND B.START_TIME < SYSDATE - 10 / 60 / 24
                         AND O.STATE NOT IN ('993890', '999990')
                         AND O.RECEIVER IN (SELECT RECEIVER_ID
                                              FROM (  SELECT MAX (CREATION_DATE) AS CREATION_DATE, 
                                                             RECEIVER_ID
                                                        FROM MYTABLE.RECEIVER_AVAILABILITY
                                                    GROUP BY RECEIVER_ID) MAX_CREATION_DATE
                                              INNER JOIN MYTABLE.RECEIVER_AVAILABILITY ON MAX_CREATION_DATE.CREATION_DATE = CREATION_DATE
                                              WHERE state IN (1, 2)
                                                AND creation_date < SYSDATE - 30 / 60 / 24)
 union all 
 select 0 as result
   from dual)
order by result desc nulls last
fetch next 1 row only;

我看到您在数据库中有分区。这意味着您使用的是企业版。我建议您使用 dbms_sqltune.report_sql_monitor(sql_id) 函数进行调整。它会向您显示预期的行数和每一步获得的行数。只需注意差异最大的步骤

【讨论】:

  • 谢谢 ekochergin,我会检查一下调整功能,这听起来很有希望。我已尝试运行您的查询,但成本和执行时间猛增:Plan SELECT STATEMENT ALL_ROWSCost: 85.225.267 Bytes: 19 Cardinality: 1 31 VIEW SYS。成本:85.225.267 字节:19 基数:1
  • 嗨 Ronald,那么最好有跟踪文件或该调整函数的输出以便继续查询优化
  • 最好的方法是获取 SQL Monitor 报告。这将向您显示估计的基数与实际基数。如果执行计划不佳,基数差异通常是问题的一部分
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-14
  • 2012-03-03
  • 2019-08-18
  • 1970-01-01
  • 1970-01-01
  • 2022-01-15
  • 1970-01-01
相关资源
最近更新 更多