【问题标题】:What is SYS_OP_UNDESCEND and SYS_OP_DESCEND in Oracle Explain Plan?Oracle 解释计划中的 SYS_OP_UNDESCEND 和 SYS_OP_DESCEND 是什么?
【发布时间】:2020-11-24 18:57:02
【问题描述】:

我有一个如下所示的 Oracle 解释计划:

Plan hash value: 2484140766                                                                               
                                                                                                          
--------------------------------------------------------------------------------------------------------  
| Id  | Operation                      | Name                  | Rows  | Bytes | Cost (%CPU)| Time     |  
--------------------------------------------------------------------------------------------------------  
|   0 | SELECT STATEMENT               |                       |   180K|    84M|     5   (0)| 00:00:01 |  
|*  1 |  COUNT STOPKEY                 |                       |       |       |            |          |  
|   2 |   VIEW                         |                       |   180K|    84M|     5   (0)| 00:00:01 |  
|*  3 |    TABLE ACCESS BY INDEX ROWID | OSTRICH               |  6500K|   793M|     5   (0)| 00:00:01 |  
|*  4 |     INDEX RANGE SCAN DESCENDING| OSTRICH_ENDDATE_IDX_2 |     1 |       |     4   (0)| 00:00:01 |  
--------------------------------------------------------------------------------------------------------  
                                                                                                          
Predicate Information (identified by operation id):                                                       
---------------------------------------------------                                                       
                                                                                                          
   1 - filter(ROWNUM<=180000)                                                                             
   3 - filter("OSTRICH_STATUS_ID"=2)                                                                      
   4 - access(SYS_OP_DESCEND("END_DATE")>=SYS_OP_DESCEND(SYSDATE@!))                                      
       filter(SYS_OP_UNDESCEND(SYS_OP_DESCEND("END_DATE"))<=SYSDATE@!)

我一直试图了解底部的这两行发生了什么:

4 - access(SYS_OP_DESCEND("END_DATE")>=SYS_OP_DESCEND(SYSDATE@!))                                      
       filter(SYS_OP_UNDESCEND(SYS_OP_DESCEND("END_DATE"))<=SYSDATE@!)

SYS_OP_UNDESCENDSYS_OP_DESCEND 是什么意思?

解释计划引用的索引(我认为)称为降序索引。 (我对 Oracle 索引了解不多。)该索引的 DDL 是:

CREATE INDEX
    OSTRICH_ENDDATE_IDX_2
ON
    OSTRICH
    (
        "END_DATE" DESC
    );

实际查询如下所示:

SELECT
 l.id,
 l.end_date,
 l.status
FROM
    (
        SELECT
            *
        from OSTRICH l2
        where END_DATE <= SYSDATE
            and OSTRICH_STATUS_ID = 2
        order by l2.END_DATE
    ) l
WHERE ROWNUM <= 180000;

SYS_OP_UNDESCENDSYS_OP_DESCEND 是什么意思?此查询花费的时间比我预期的要长得多,我正在尝试了解降序和降序对查询的影响?

【问题讨论】:

  • END_DATE 是否是虚拟列?
  • 它不是虚拟列

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


【解决方案1】:

Oracle 实现了降序索引"as if" it were a function-based index。当查询使用函数调用时,会调用基于函数的索引;因此,当 WHERE 子句过滤 upper(col1) = 'WHATEVER' 时,将使用 upper(col1) 上的 FBI。

在这种情况下,我认为 SYS_OP_DESCEND 是 Oracle 在创建降序索引时使用的“函数”,我认为它随后会调用 SYS_OP_UNDESCEND,因为您的 WHERE 子句不适合降序索引。性能很差也就不足为奇了。

很少有使用降序索引是个好主意的用例。你为什么在这张表的这一列上使用一个?

假设使用索引有充分的理由并且您不能直接放弃它,那么提高性能的最佳选择是不使用索引进行此查询。这样做应该可以防止优化器不使用索引:

SELECT
 l.id,
 l.end_date,
 l.status
FROM
    (
        SELECT /*+ NO_INDEX(l2 OSTRICH_ENDDATE_IDX_2) */ 
            *
        from OSTRICH l2
        where END_DATE <= SYSDATE
            and OSTRICH_STATUS_ID = 2
        order by l2.END_DATE
    ) l
WHERE ROWNUM <= 180000;

【讨论】:

  • 感谢您的解释和建议。我只需要澄清一下。当您说upper_col(1) 时,upper 指的是什么?
  • 回答你关于为什么使用这个索引的问题,我是这个代码库的新手,但从数据库中的其他一些索引来看,我认为这不是那个打算使用,或者至少我认为我为此查询找到了更好的索引。我将使用索引提示来测试其他索引是否会更好。
  • UPPER(col1) 只是我们如何使用实际基于函数的索引的一个示例。
  • 你是否知道为什么在解释计划的最后一行,行数是1。下面是最后一行:|* 4 | INDEX RANGE SCAN DESCENDING| OSTRICH_ENDDATE_IDX_2 | 1 | | 4 (0)| 00:00:01 |
【解决方案2】:

SYS_OP_UNDESCENDSYS_OP_DESCEND是 CBO 使用的内部函数,当使用基于函数的索引或指定索引子句内的排序操作时,它们出现在 EXPLAIN PLAN 中。

在您的情况下,您使用的是带有 SORT 子句的 INDEX

CREATE INDEX
    OSTRICH_ENDDATE_IDX_2
ON
    OSTRICH
    (
        "END_DATE" DESC
    );

你的计划显示了这两个操作:

  • access(SYS_OP_DESCEND("END_DATE")&gt;=SYS_OP_DESCEND(SYSDATE@!))
  • filter(SYS_OP_UNDESCEND(SYS_OP_DESCEND("END_DATE"))&lt;=SYSDATE@!)

第一个操作是访问,基于索引本身的 desc 索引子句,第二个操作是过滤器。两者都出现是因为查询是针对索引的性质进行的。

我永远不会在任何索引中使用此子句,除非始终以这种方式完成访问,这非常罕见,因为以不同方式排序是 SQL 通常用于的用途。

还有这个bug:(20.1修复)

错误 27589260 由于基于函数的索引中的虚拟列替换导致排序顺序错误

当表中存在虚拟列并且使用了基于函数的索引时,这会降低查询的性能。

【讨论】:

  • 感谢您的回答,罗伯托。关于您在这里所说的:“当表中存在虚拟列并且使用了基于函数的索引时,这会降低查询的性能。”我不熟悉您所说的基于函数的索引是什么意思。根据我上面给出的索引定义,我的索引函数是基于吗?
  • 对于这一行:filter(SYS_OP_UNDESCEND(SYS_OP_DESCEND("END_DATE"))&lt;=SYSDATE@!),CBO 实际上是在做 2 种不同的排序(一种降序,一种升序)吗?如果是这样,它是什么排序?是对查询的索引还是结果进行排序?
  • @fozzy_bear_waka_waka,基于函数的索引是使用任何类型的函数对作为索引的列进行计算/转换的索引。当您使用“desc”选项创建索引时,它会将索引创建为基于复合函数的索引。
  • @fozzy_bear_waka_waka,关于您的第二个问题,它正在过滤您要求过滤的内容:END_DATE &lt;= SYSDATE。要与 SYSDATE 进行比较,首先需要对数据进行 UNDESCEND,表达式SYS_OP_DESCEND("END_DATE") 是基于函数的索引本身
  • 你知道是降序索引还是实际数据?
猜你喜欢
  • 2011-03-03
  • 2020-01-08
  • 1970-01-01
  • 2012-11-12
  • 2012-12-16
  • 1970-01-01
  • 1970-01-01
  • 2017-11-05
相关资源
最近更新 更多