【问题标题】:pl/sql query optimization with function call in where clause在 where 子句中使用函数调用进行 pl/sql 查询优化
【发布时间】:2014-05-17 04:03:59
【问题描述】:

我正在尝试优化我在 where 子句中使用 function() 调用的查询。

function() 只是更改日期的时区。

当我将函数作为 SELECT 的一部分调用时,它的执行速度非常快(对于数十万行的表来说,

select 
  id, 
  fn_change_timezone (date_time, 'UTC', 'US/Central') AS tz_date_time,
  value 
from a_table_view
where id = 'keyvalue'
and date_time = to_date('01-10-2014','mm-dd-yyyy')

但是,这个版本“永远”运行[意味着我在无数分钟后停止它]

select id, date_time, value 
from a_table_view
where id = 'keyvalue'
and fn_change_timezone (date_time, 'UTC', 'US/Central')  = to_date('01-10-2014','mm-dd-yyyy')

(我知道我必须更改被比较的日期,这只是示例)

所以我的问题有两个:

  1. 如果函数在 where 子句之外如此之快,为什么它比使用 TRUNC() 或其他函数慢得多(显然 trunc() 不像我的函数那样进行表查找 - 但仍然是函数在where子句之外非常非常快)

  2. 在 where 子句之外有哪些替代方法可以完成此任务?

我尝试了这个作为替代方案,但似乎并没有更好,它仍然运行,直到我停止查询:

select
  tz.date_time,
  v.id, 
  v.value
from 
  (select
    fn_change_timezone(to_date('01/10/2014-00:00:00', 'mm/dd/yyyy-hh24:mi:ss'), 'UTC',     'US/Central') as date_time
    from dual
    ) tz
  inner join   
 (
  select 
    id, 
    fn_change_timezone (date_time, 'UTC', 'US/Central') AS v_date_time,
    value 
  from a_table_view
  where id = 'keyvalue'
  ) v ON
    v.tz_date_time = tz.date_time

希望我能很好地解释这个问题。

【问题讨论】:

  • 您的函数是作为“不变量”还是“常量”函数创建的?这告诉优化器不需要为每组相同的参数重新调用函数。
  • 我不理解那些与 Oracle 函数相关的术语。当我搜索时,Google 没有帮助。
  • 对不起,我的错误,你想看看“确定性函数”。 dba-oracle.com/plsql/t_plsql_deterministic.htm
  • 如果我理解正确 - 该函数不是用 DETERMINISTIC 关键字定义的,并且它总是会根据相同的输入值返回相同的值。它只是做一个表查找,并执行一个 from_tz() 和一些 cast()'ing
  • 你能把函数重新定义为 DETERMINISTIC 吗?如果是这样,那应该对优化器有所帮助。此外,如果函数在幕后进行表查找,这也会使事情变慢。

标签: oracle function plsql query-optimization where-clause


【解决方案1】:

WHERE 子句中使用函数至少有四个潜在问题:

  1. 函数可能会阻止索引。基于函数的索引可以解决这个问题。
  2. 函数可能会阻止分区修剪。硬编码值或虚拟列分区是可能的解决方案,尽管在这种情况下都可能没有帮助。
  3. 函数可能运行缓慢。 即使函数很便宜,在 SQL 和 PL/SQL 之间切换通常也很昂贵。一些可能的解决方案是DETERMINISTICPARALLEL_ENABLE、函数结果缓存、在纯 SQL 中定义逻辑,或使用 12c 在 SQL 中定义函数。
  4. 函数可能会导致错误的基数估计。 优化器很难猜测正常条件的结果,添加过程代码使其更加困难。使用ASSOCIATE STATISTICS 可以向优化器提供有关函数成本和基数的一些信息。

没有更多信息,例如解释计划,很难知道这个查询的具体问题是什么。

【讨论】:

  • 明白了,where 子句中的函数调用对我来说很糟糕,而且不容易优化。这就是为什么我正在寻找替代品。不幸的是,我无法将函数更改为确定性,因此很可能我将不得不找到另一种方法来消除函数调用。
  • 如果没有解释计划,很难判断哪个选项会有所帮助。您甚至可能不一定需要更改函数,也许只需更改 Oracle 调用函数的方式(间接通过选项 #4)。
【解决方案2】:

WHERE 子句中的函数调用是一件坏事。问题是可能会为表中的每一行调用该函数,这可能比选定的集合多得多。这可能是一个真正的性能杀手(不要问我是怎么知道的 :-)。在第一个版本中,函数调用在 SELECT 列表中,只有在选择了一行并将其添加到结果集中时才会调用该函数 - 在第二个版本中,很可能会为表中的每一行调用该函数。此外,根据您使用的 Oracle 版本,从 SQL 调用用户函数可能会产生大量开销,但我认为自 10g 以来的版本已基本消除了这种损失。

祝你好运。

分享和享受。

【讨论】:

    猜你喜欢
    • 2021-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多