为什么只有当我使用 where 子句查询子查询时,Oracle 10g SQL 才运行缓慢?
由于各种原因,我无法粘贴整个 SQL,因此请考虑以下示例:
select *
from
(select nvl(get_quantity(1), 10) available_qty
from dual)
where available_qty > 30;
get_quantity
是一个函数,它根据通过它的记录的 ID 进行计算。如果它返回 null,我会使用 nvl()
将其强制为 10。
当我在父查询中使用 WHERE 子句时,查询运行速度非常慢。然而,当我注释掉 WHERE
子句时,它运行得非常快。我不明白的是为什么它可以非常快地显示数据,但不能同样快地查询数据。我也在查询子查询的结果。我的印象是子查询返回“渲染”数据集。这几乎就像查询 available_qty 标识符导致它引用子查询中的某些内容一样。
这就是为什么我认为 get_quantity 函数的内容与这里无关,所以我没有费心发布它。相反,我认为这是我对 Oracle 如何处理子查询等的误解。
你们中的 Oracle 专家知道我做错了什么吗?
事后思考:当我为这个问题输入标签时,出现了“相关子查询”标签。在进行一些快速研究时,似乎这种类型的子查询在某种程度上取决于外部查询。这可能与我的问题有关吗?
I can't paste in the entire SQL for various reasons, so consider this example:
select *
from
(select nvl(get_quantity(1), 10) available_qty
from dual)
where available_qty > 30;
get_quantity
is a function that makes a calculation based on the ID of a record that's passed through it. If it returns null, I use nvl()
to force it to 10.
The query runs very slow when I use the WHERE clause in the parent query. When I comment out the WHERE
clause, however, it runs very fast. What I don't get is why it can display the data very fast, but it can't query it just as fast. I am querying the results of a subquery, too. I was under the impression that subqueries return a "rendered" dataset. It's almost as if querying the available_qty identifier is causing it to reference something within the subquery.
This is why I don't think the contents of the get_quantity function are relevant here, so I didn't bother posting it. Instead, I think it's a misunderstanding on my part of how Oracle handles subqueries and whatnot.
Do any of you Oracle gurus have any idea what I am doing wrong?
Afterthought: as I was entering tags for this question, the tag "correlated subquery" came up. In doing some quick research, it seems that this type of subquery somewhat depends on the outer query. Could this be related to my problem?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我们来做个实验吧。首先,我们将运行以下查询:
“a”子查询将返回 5 行,其值从 1 到 5。“b”子查询将返回具有随机值的一行。如果该函数在两个表连接(通过笛卡尔)之前运行,则每行将返回相同的随机值。实际结果:
显然,该函数是针对每个连接的行运行的,而不是针对连接之前的子查询运行的。这是 Oracle 优化器决定查询的最佳路径是按该顺序执行操作的结果。为了防止这种情况,我们必须在第二个子查询中添加一些内容,使 Oracle 在执行联接之前完整地运行子查询。我们将把 rownum 添加到子查询中,因为 Oracle 知道如果在连接之后运行 rownum 将会改变。以下查询演示了这一点:
正如您从结果中看到的,在这种情况下该函数仅运行一次:
在您的情况下,
where
子句提供的过滤器似乎正在使优化器采用不同的路径,重复运行该函数,而不是一次。通过让 Oracle 按照编写的方式运行子查询,您应该获得更一致的运行时间。Let's try an experiment. First we'll run the following query:
The "a" subquery will return 5 rows with values from 1 to 5. The "b" subquery will return one row with a random value. If the function is run before the two tables are join (by Cartesian), the same random value will be returned for each row. The actual results:
Clearly the function was run for each of the joined rows, not for the subquery before the join. This is a result of Oracle's optimizer deciding that the best path for the query is to do things in that order. To prevent this, we have to add something to the second subquery that will make Oracle run the subquery in it's entirety before performing the join. We'll add rownum to the subquery, since Oracle knows rownum will change if it's run after the join. The following query demonstrates this:
As you can see from the results, the function was only run once in this case:
In your case, it seems likely that the filter provided by the
where
clause is making the optimizer take a different path, where it's running the function repeatedly, rather than once. By making Oracle run the subquery as written, you should get more consistent run-times.