由于各种原因,我无法粘贴整个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如何处理子查询之类的误解。
你们中有谁知道我做错了什么吗?
事后考虑:当我为这个问题输入标记时,出现了“关联子查询”标记。在进行一些快速研究时,这种类型的子查询似乎在一定程度上取决于外部查询。这跟我的问题有关吗?
发布于 2011-06-16 11:42:13
我们来做个实验吧。首先,我们将运行以下查询:
select lvl, rnd
from (select level as lvl from dual connect by level <= 5) a,
(select dbms_random.value() rnd from dual) b;
"a“子查询将返回值为1到5的5行,"b”子查询将返回带有随机值的一行。如果函数在连接两个表之前运行(按笛卡尔方式),则将为每一行返回相同的随机值。实际结果:
LVL RND
---------- ----------
1 .417932089
2 .963531718
3 .617016889
4 .128395638
5 .069405568
5 rows selected.
显然,函数是为每个已连接的行运行的,而不是针对联接之前的子查询运行的。这是Oracle的优化器决定查询的最佳路径是按该顺序执行操作的结果。为了防止这种情况,我们必须在第二个子查询中添加一些内容,这将使Oracle在执行联接之前完整地运行子查询。我们将把rownum添加到子查询中,因为Oracle知道如果在连接之后运行rownum,它会改变。下面的查询说明了这一点:
select lvl, rnd from (
select level as lvl from dual connect by level <= 5) a,
(select dbms_random.value() rnd, rownum from dual) b;
从结果中可以看到,该函数在本例中只运行了一次:
LVL RND
---------- ----------
1 .028513902
2 .028513902
3 .028513902
4 .028513902
5 .028513902
5 rows selected.
在您的示例中,where
子句提供的筛选器可能会使优化器采用不同的路径,在那里它会重复运行函数,而不是一次。通过让Oracle按编写的方式运行子查询,您应该可以获得更一致的运行时间。
https://stackoverflow.com/questions/6377209
复制相似问题