我有一个类似的查询:
SELECT id, value
FROM very_large_table -- over 5 million records
WHERE foo(value) > 5 AND boo(value) IS NOT NULL
假设foo
和boo
是函数,这也会在没有索引的超大表上进行大量选择(因此执行成本很高)。
我(作为程序员)知道,99%的时间内foo
的回复率超过5,但boo
的回报率为{99},NULL
。
很明显,首先应该计算boo
。如果是NULL
,我们不希望结果集中包含此行。所以我们不需要计算foo
,因为boo
已经NULL
。
是否有关于此主题的任何包/文章,因为,如果我做得对 - oracle不做这种优化
以上只是一个例子。在我的情况下,有很多功能(~50),我在各种组合的各种选择中使用它们。所以重写函数并不是真正的选择,因为在实际情况中有很多它们:我只是想表明这些请求真的很慢。我只想到某种优化器(除了oracle之外)
答案 0 :(得分:7)
Oracle可以进行这种优化,但需要使用勺子 它被称为Oracle Extensible Optimizer和associate 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)
我曾经遇到过类似的问题。在我的情况下,我只有一个函数,但它是一个邪恶的:应用程序用于名称匹配,函数返回一个分数,表明行的值和用户输入之间的相似性。有些名称非常常见或匹配许多不同的变体,因此返回了数千行,其他名称将返回少量或非返回。该表非常庞大,没有索引范围,因为我们无法映射所有可能的用户输入。
除了索引之外,还有许多其他的优化机制。
FOO()
得分大于4.所以你可以提取这些标记 - 在连接中使用的单独表中或作为列(在11g中作为虚拟列)列)您可以索引。您需要将这些令牌过滤器添加到查询中,可能是动态的。显然,这只适用于某些类型的数据。适用于所有版本。 BOO()
过滤掉大部分行,FOO()
几乎没有。因此,BOO()
上的索引将是非常优化的,并且FOO()
上的索引比无用的更糟糕。因此,请查看您的函数:确定哪些函数具有高选择性并且最常用,并为它们构建基于函数的索引。适用于所有版本。 如您所见,许多优化需要企业版。好吧,甲骨文希望你能够购买更昂贵的许可证,这就是他们限制酷炫功能的原因。标准版中的优化需要我们付出更多努力。
我是如何解决我的问题的?好吧,我在9i,所以结果集缓存不适合我,但那是我真正想要的。不幸的是,我有太多的并发用户可以进行并行查询。我的最终解决方案是令牌化和复杂索引结构的混合。