oracle:如何确保只有在所有剩余的where子句筛选出结果后才会调用where子句中的函数?

Dau*_*aud 12 oracle optimization function filter

我正在写这个效果的查询:

select * 
from players 
where player_name like '%K% 
  and player_rank<10 
  and check_if_player_is_eligible(player_name) > 1;
Run Code Online (Sandbox Code Playgroud)

现在,函数check_if_player_is_eligible()很重,因此,我希望查询充分过滤搜索结果,然后只对过滤后的结果运行此函数.

如何确保在执行函数之前进行所有过滤,以便它运行的次数最少?

Vin*_*rat 16

这里有两种方法可以让你在评估所有其他WHERE子句之前欺骗Oracle不评估你的函数:

  1. 使用rownum

    rownum在子查询中使用伪列将强制Oracle"实现"子查询.例如,请参阅这个askTom线程.

    SELECT *
      FROM (SELECT *
               FROM players
              WHERE player_name LIKE '%K%'
                AND player_rank < 10
                AND ROWNUM >= 1)
     WHERE check_if_player_is_eligible(player_name) > 1
    
    Run Code Online (Sandbox Code Playgroud)

    这是文档参考"Unesteding of Nested Subqueries":

    除了一些例外,优化器可以取消大多数子查询.这些异常包括分层子查询和包含ROWNUM伪列的子查询,集合运算符之一,嵌套聚合函数或对查询块的相关引用,该查询块不是子查询的直接外部查询块.

  2. 使用CASE

    使用CASE可以强制Oracle仅在其他条件评估为TRUE时评估您的函数.不幸的是,如果你想利用其他子句来使用索引,它会涉及重复代码,如:

    SELECT *
      FROM players
     WHERE player_name LIKE '%K%'
       AND player_rank < 10
       AND CASE 
             WHEN player_name LIKE '%K%'
              AND player_rank < 10 
                THEN check_if_player_is_eligible(player_name) 
           END > 1
    
    Run Code Online (Sandbox Code Playgroud)