我在游标中使用的Oracle select语句存在性能问题。在语句中,SELECT
子句中的一个术语的评估成本很高(它是一个PL / SQL过程调用,它非常重要地访问数据库)。但是,WHERE
子句和ORDER BY
子句很简单。
我希望Oracle首先执行WHERE
子句来识别与查询匹配的记录集,然后执行ORDER BY
子句对它们进行排序,最后评估每个术语中的每个术语。 SELECT
条款。当我在游标中使用此语句然后从中拉取结果时,我预计只有在从游标请求每个结果时才会根据需要执行昂贵的SELECT
项评估。
但是,我发现这不是Oracle使用的序列。相反,它似乎在执行排序之前为每个匹配WHERE子句的记录评估SELECT
子句中的术语。因此,在从游标返回任何结果之前,将为结果集中的每个结果调用调用昂贵的过程。
我希望能够尽快从游标中获取第一个结果。任何人都可以告诉我如何说服Oracle在SELECT语句中评估过程调用,直到执行排序之后?
这可能更容易在示例代码中描述:
给定一个包含example
,a
,b
和c
列的表d
,我的声明如下:
select a, b, expensive_procedure(c)
from example
where <the_where_clause>
order by d;
执行此操作时,将为匹配expensive_procedure()
子句的每条记录调用WHERE
,即使我将该语句作为游标打开并仅从中拉出一个结果。
我尝试将声明重组为:
select a, b, expensive_procedure(c)
from example, (select example2.rowid, ROWNUM
from example example2
where <the_where_clause>
order by d)
where example.rowid = example2.rowid;
内部ROWNUM
语句中SELECT
的存在迫使Oracle首先对其进行评估。这种重组具有理想的性能优势。不幸的是,它并不总是尊重所需的顺序。
为了清楚起见,我知道我不会改善返回整个结果集所需的时间。我希望改善从声明中返回前几个结果所花费的时间。我希望所花费的时间是渐进式的,因为我会迭代光标的结果,而不是在返回第一个结果之前全部过去。
任何Oracle专家都可以告诉我如何说服Oracle在必要时停止执行PL / SQL吗?
答案 0 :(得分:2)
为什么在内联视图中将EXAMPLE连接到自身?为什么不呢:
select /*+ no_merge(v) */ a, b, expensive_procedure(c)
from
( select a, b, c
from example
where <the_where_clause>
order by d
) v;
答案 1 :(得分:1)
这是否符合您的意图?
WITH
cheap AS
(
SELECT A, B, C
FROM EXAMPLE
WHERE <the_where_clause>
)
SELECT A, B, expensive_procedure(C)
FROM cheap
ORDER BY D
答案 2 :(得分:0)
您可能想尝试一下
select a, b, expensive_procedure(c)
from example, (select /*+ NO_MERGE */
example2.rowid,
ROWNUM
from example example2
where <the_where_clause>
order by d)
where example.rowid = example2.rowid;
答案 3 :(得分:0)
这可能是某种形式的工作吗?
FOR R IN (SELECT a,b,c FROM example WHERE ...) LOOP
e := expensive_procedure(R.c);
...
END LOOP;
答案 4 :(得分:0)
如果您的WHERE
条件是平等的,i。即
WHERE col1 = :value1
AND col2 = :value2
您可以在(col1, col2, d)
上创建综合索引:
CREATE INDEX ix_example_col1_col2_d ON example(col1, col2, d)
并提示您的查询使用它:
SELECT /*+ INDEX (e ix_example_col1_col2_d) */
a, b, expensive_procedure(c)
FROM example e
WHERE col1 = :value1
AND col2 = :value2
ORDER BY
d
在下面的示例中,t_even
是一个1,000,000
行表,其索引位于value
。
从此查询中获取100
列:
SELECT SYS_GUID()
FROM t_even
ORDER BY
value
是即时(0,03
秒),而这一个:
SELECT SYS_GUID()
FROM t_even
ORDER BY
value + 1
需要大约170
秒来获取第一行100
。
SYS_GUID()
中, Oracle
相当昂贵
正如其他人所建议的那样,你也可以使用它:
SELECT a, b, expensive_proc(c)
FROM (
SELECT /*+ NO_MERGE */
*
FROM mytable
ORDER BY
d
)
,但使用索引会改善查询响应时间(返回第一行的时间)。
答案 5 :(得分:0)
我们尝试过的解决方案的一个关键问题是如何调整生成SQL的应用程序以正确构建查询。构建的SQL将根据检索的列数,where子句中的条件数量和类型以及顺序中的表达式的数量和类型而变化。
返回ROWID以加入外部的内联视图是我们可以使用的几乎完全通用的解决方案,除非搜索返回了大部分数据。在这种情况下,优化器[正确]决定HASH连接比NESTED LOOP便宜。
另一个问题是涉及的一些对象是不能有ROWID的VIEW。
有关信息:“D”不是拼写错误。未按顺序选择order by的表达式作为返回值的一部分。不是一件不寻常的事情:
select index_name, column_name
from user_ind_columns
where table_name = 'TABLE_OF_INTEREST'
order by index_name, column_position;
在这里,您不需要知道column_position,但按其排序至关重要。
我们有理由(我们不会让读者感到厌烦)避免在解决方案中提示,但看起来并非如此。
感谢迄今为止的建议 - 我们已经尝试了大部分建议......