Oracle函数的优化器

时间:2011-06-12 04:49:25

标签: oracle optimization

我有一个类似的查询:

SELECT id, value
FROM very_large_table -- over 5 million records 
WHERE foo(value) > 5 AND boo(value) IS NOT NULL

假设fooboo是函数,这也会在没有索引的超大表上进行大量选择(因此执行成本很高)。

我(作为程序员)知道,99%的时间内foo的回复率超过5,但boo的回报率为{99},NULL。 很明显,首先应该计算boo。如果是NULL,我们不希望结果集中包含此行。所以我们不需要计算foo,因为boo已经NULL

是否有关于此主题的任何包/文章,因为,如果我做得对 - oracle不做这种优化


以上只是一个例子。在我的情况下,有很多功能(~50),我在各种组合的各种选择中使用它们。所以重写函数并不是真正的选择,因为在实际情况中有很多它们:我只是想表明这些请求真的很慢。我只想到某种优化器(除了oracle之外)

4 个答案:

答案 0 :(得分:7)

Oracle可以进行这种优化,但需要使用勺子 它被称为Oracle Extensible Optimizerassociate statistics

但在这种情况下,这样做的简单方法就是这样

where case when boo(value) is null then 0 else foo(value) end > 5

强制在foo之前评估boo函数。

如果您无法控制查询(例如,使用某些BI工具),则高级内容将适用。另一个原因是,如果你有一堆编码器,那么开发那种理解会过度,并且让一两个'数据库人'管理这方面的事情会更容易。

答案 1 :(得分:2)

只需编写运行boofoo的函数boo,然后仅当foo不为空时才编写boo

要进一步调整,可以在该表/列上添加基于函数的索引:

create index vlt_boofoo on very_large_table (boofoo(value));

答案 2 :(得分:2)

如果您使用的是Oracle 11 Enterprise,Result Cache可以提供帮助。这会在执行后缓存函数的结果,除非基础表中的数据发生变化,否则不会再次执行它们。


如果这不起作用,您可以尝试将VIEW的函数替换为该表(假设您从多个地方调用函数 - 否则您可以加入表格。)

这将允许加入这些视图而不是使用函数,这可能允许优化器仅在您的函数的每次调用中查询一次大表而不是一次。

所以而不是

CREATE FUNCTION foo( in_value IN very_large_table.value%TYPE )
  RETURN PLS_INTEGER
AS
  v_count PLS_INTEGER;
BEGIN
  SELECT COUNT(*)
  INTO v_count
  FROM some_other_large_table
  WHERE value = in_value;

  RETURN v_count;
END foo;

你可以

CREATE VIEW view_foo AS
  SELECT value, COUNT(*)
  FROM some_other_large_table
  GROUP BY value;

加入

SELECT t.id, t.value
FROM very_large_table t -- over 5 million records
JOIN view_foo foo ON ( foo.value = t.value )
JOIN view_boo ...

答案 3 :(得分:1)

我曾经遇到过类似的问题。在我的情况下,我只有一个函数,但它是一个邪恶的:应用程序用于名称匹配,函数返回一个分数,表明行的值和用户输入之间的相似性。有些名称非常常见或匹配许多不同的变体,因此返回了数千行,其他名称将返回少量或非返回。该表非常庞大,没有索引范围,因为我们无法映射所有可能的用户输入。

除了索引之外,还有许多其他的优化机制。

  1. 并行查询。一种强力解决方案,如果您的数据库服务器拥有大量CPU并且您没有多个用户想要同时查询该表,则该解决方案很有效。需要Enterprise Edition许可证。
  2. 分区。如果您有其他条件来过滤查询(创建日期或某些内容),那么您可以应用分区修剪来减少查询的范围。分区不是自动获得的性能:它主要是一种管理选项,可能会降低与分区键相关的查询性能。需要Enterprise Edition许可证和分区选项,因此昂贵的
  3. 服务器结果集缓存。在11g中我们可以将查询/子查询或函数的结果存储在内存中;我们支付执行一次的成本,所有后续查询立即返回结果集。这对于确定性函数和缓慢变化的表格很有用。 Find out more。它以内存换取性能。需要11g和Enterprise Edition许可证。
  4. 物化视图。我们可以使用MView预先计算某些查询的结果,优化器会通过QUERY REWRITE功能自动使用它们。同样,这适用于缓慢变化的表格。它交换磁盘空间以提高性能。需要Enterprise Edition许可证。
  5. 标记化即可。某些值可能具有与函数返回的值相关的公共元素。例如,以'Z'开头的值永远不会有FOO()得分大于4.所以你可以提取这些标记 - 在连接中使用的单独表中或作为列(在11g中作为虚拟列)列)您可以索引。您需要将这些令牌过滤器添加到查询中,可能是动态的。显然,这只适用于某些类型的数据。适用于所有版本。
  6. 索引其他列。一个穷人的分区,但是如果您在查询中使用了其他列,请考虑在应用函数之前是否可以使用其中任何一个来约束结果集。适用于所有版本。
  7. 基于函数的索引。我知道您已经打折了此选项,但您应该重新考虑。您不需要为每个函数构建索引。在示例中,您将BOO()过滤掉大部分行,FOO()几乎没有。因此,BOO()上的索引将是非常优化的,并且FOO()上的索引比无用的更糟糕。因此,请查看您的函数:确定哪些函数具有高选择性并且最常用,并为它们构建基于函数的索引。适用于所有版本。
  8. 如您所见,许多优化需要企业版。好吧,甲骨文希望你能够购买更昂贵的许可证,这就是他们限制酷炫功能的原因。标准版中的优化需要我们付出更多努力。

    我是如何解决我的问题的?好吧,我在9i,所以结果集缓存不适合我,但那是我真正想要的。不幸的是,我有太多的并发用户可以进行并行查询。我的最终解决方案是令牌化和复杂索引结构的混合。