【问题标题】:Oracle EBS expression on indexed column prevents use of index索引列上的 Oracle EBS 表达式阻止使用索引
【发布时间】:2018-10-07 07:39:53
【问题描述】:

Oracle 数据库 11.1.0.7 和 EBS 应用程序 11.5.10。

我有一个性能不佳的自定义视图,其中包括 Oracle EBS 基础视图 APPS.RA_CUSTOMER_TRX。此基础视图针对的是基础表 RA_CUSTOMER_TRX_ALL,如下所示。

FROM RA_CUSTOMER_TRX_ALL
     WHERE NVL (
               ORG_ID,
               NVL (
                   TO_NUMBER (
                       DECODE (SUBSTRB (USERENV ('CLIENT_INFO'), 1, 1),
                               ' ', NULL,
                               SUBSTRB (USERENV ('CLIENT_INFO'), 1, 10))),
                   -99)) =
           NVL (
               TO_NUMBER (
                   DECODE (SUBSTRB (USERENV ('CLIENT_INFO'), 1, 1),
                           ' ', NULL,
                           SUBSTRB (USERENV ('CLIENT_INFO'), 1, 10))),
               -99);

当我从 Toad 针对自定义视图的 sql 运行 Oracle Tuning Advisor 时,它会告诉我

1- Restructure SQL finding (see plan 1 in explain plans section)
----------------------------------------------------------------
  The predicate NVL("RA_CUSTOMER_TRX_ALL"."ORG_ID",NVL(TO_NUMBER(DECODE(SUBSTRB
  (USERENV('CLIENT_INFO'),1,1),' ',NULL,SUBSTRB(USERENV('CLIENT_INFO'),1,10))),
  (-99)))=NVL(TO_NUMBER(DECODE(SUBSTRB(USERENV('CLIENT_INFO'),1,1),'
  ',NULL,SUBSTRB(USERENV('CLIENT_INFO'),1,10))),(-99)) used at line ID 53 of
  the execution plan contains an expression on indexed column "ORG_ID". This 
  expression prevents the optimizer from efficiently using indices on table
  "AR"."RA_CUSTOMER_TRX_ALL".

  Recommendation
  --------------
  - Rewrite the predicate into an equivalent form to take advantage of
    indices. Alternatively, create a function-based index on the expression.

  Rationale
  ---------
    The optimizer is unable to use an index if the predicate is an inequality
    condition or if there is an expression or an implicit data type conversion
    on the indexed column.

所以我的选择是 1) 重写自定义视图以针对基本表而不是基本视图,或者 2) 创建基于函数的索引。我尝试创建基于函数的索引,但它告诉我“只能索引纯函数。”

我想通过创建索引来解决这个问题,因为我相信其他类似的观点也会从中受益。我的 DBA 技能还不够高,所以希望有人以前遇到过这个问题并可以提供建议。

谢谢。

【问题讨论】:

  • 您的设置中有多个组织吗?
  • 是的,多个组织。
  • 哦,那太难了,因为您必须从会话中获取组织 ID。是否有任何其他可以索引的过滤条件?或者是否有另一个表可以用来驱动查询
  • 自定义视图适用于特定的组织/国家,因此我可以在自定义视图中对其进行硬编码。如果我采用选项 1) 并重写自定义视图以反对基表,这将是计划。
  • 对我来说这听起来像是一个更好的计划(使用 ra_customer_trx_all 并硬编码 org id)。无法创建基于函数的索引,因为 userenv('client_id') 调用正在读取在会话建立后设置的值——这就是 oracle 如何为多个组织提供行级安全性

标签: oracle view oracle11g sql-tuning


【解决方案1】:

NVL 不会短路,因此您的整个表达式总是被完整地评估,包括对 USERENV 的三个调用。我也不清楚您的 CLIENT_INFO 字符串的格式会是什么样子。我假设它是一个数字或空白。我还没有完全解决这个问题,但是你能把 where 子句改成更像:

WHERE ( org_id IS NOT NULL AND USERENV ('CLIENT_INFO') IS NOT NULL AND
        org_id = TO_NUMBER( USERENV ('CLIENT_INFO')))
   OR ( org_id IS NOT NULL AND USERENV ('CLIENT_INFO') IS NULL AND org_id = -99 )
   OR ( org_id IS NULL AND USERENV ('CLIENT_INFO') IS NULL )

您也可以尝试使用公用表表达式缓存对 USERENV 的调用,但我不确定这是否会有所帮助:

WITH clientinfo AS (
    SELECT /*+ MATERIALIZE */ USERENV( 'CLIENT_INFO' ) AS client_info FROM dual
)
SELECT ...
  FROM ...
 INNER JOIN clientinfo ci
 WHERE ci.client_info = ...

【讨论】:

    猜你喜欢
    • 2011-02-13
    • 2014-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-21
    • 2015-05-27
    • 1970-01-01
    • 2020-05-06
    相关资源
    最近更新 更多