如何优化这个嵌套的 SQL SELECT 查询
Posted
技术标签:
【中文标题】如何优化这个嵌套的 SQL SELECT 查询【英文标题】:How to optimize this nested SQL SELECT query 【发布时间】:2019-04-19 13:09:38 【问题描述】:我有一个非常慢的查询,如下所示:
SELECT *
FROM (
SELECT ..., nn_key_fast(nachname) nnk, ...
FROM t1
JOIN t2 ON
...
JOIN t3 ON
...
JOIN t4 ON
...
WHERE ...
AND t4.POSTCODE='1234'
)
WHERE ... AND nnk LIKE "N%"
现在,内部选择大约需要 2 分钟。如果我删除最后一个 WHERE 子句(t4.POSTCODE),它会在 ~4 秒内执行。没有这个子句的结果将是
所以,我的想法是:将该子句移到外部 SELECT,然后它只会应用于生成的
但是没有。查询花费的时间完全一样,所以要清楚:
SELECT *
FROM (
SELECT .....
FROM t1
JOIN t2 ON
...
JOIN t3 ON
...
JOIN t4 ON
...
WHERE ...
)
WHERE ...
AND POSTCODE='1234'
与第一个版本一样需要 2 分钟。
这对我来说似乎很疯狂。
直观地说,这必须由查询优化器执行,如下所示: 从内部选择创建一个表,如下所示:
CREATE TABLE res_from_inner AS (
SELECT .....
FROM t1
JOIN t2 ON
...
JOIN t3 ON
...
JOIN t4 ON
...
WHERE ...
)
...然后只在这个表上做外部选择,像这样:
SELECT *
FROM res_from_inner
WHERE POSTCODE='1234'
如果我手动执行此操作,则 CREATE TABLE 查询需要大约 4 秒,而第二个 SELECT 需要,如预期的那样
这怎么可能,怎么办?
【问题讨论】:
我猜你的索引中没有包含邮政编码。 子查询的 select 子句中有什么 -->SELECT .....
?如果您在 SELECT 子句中使用任何函数或表达式(如 to_char( x ) as y
或 x+y as z
),然后您在 WHERE 子句中使用其结果(如 y = '123' or z=22
,那么 Oracle 无法将谓词下推到子查询、索引没用,而且一定很慢。没有详细信息,很难在这里提出任何建议,请显示完整的查询,它是execution plan,现在我投票结束你的问题,因为它太宽泛了。
@krokodilko:现在感觉有点傻……你说得对,select子句中有一个函数,计算的字段用在外层select中。但是,当我执行整个查询时,今天需要 13 秒...但是:如果我从该选择创建一个表(创建表为...),则再次需要 2 分钟。结果集中只有大约 1000 条记录。抱歉让您感到困惑,我不确定自己到底在问什么。
【参考方案1】:
您必须查看执行计划才能了解实际情况。事情正在发生变化。
您可以尝试的一件事是 CTE:
with s as (
<subquery here>
)
select s.*
from s
where . . .;
Oracle 可能会自动实现这一点。或者你可以给个提示:
with s as (
select /*+ materialize */ . . .
. . .
)
select s.*
from s
where . . .;
【讨论】:
感谢您的提示。以前从未使用过 WITH ,但这似乎相当简单。但也从未听说过 materialize-hint,这似乎从 V10g 开始就变得不必要了(据此:dba-oracle.com/t_materialize_sql_hint.htm)。有趣的东西。【参考方案2】:我尽量远离嵌套的 select 语句。在这种情况下,我会将内部 select 语句作为子查询,然后从中选择我想要的内容。
子查询为 ( 选择...从...加入...加入...加入...在哪里 )
从子查询中选择*
--希望有所帮助:]
【讨论】:
谢谢。将来会尝试将我的嵌套选择(我们经常使用它们)重构为 WITH CTE。这看起来干净多了。以上是关于如何优化这个嵌套的 SQL SELECT 查询的主要内容,如果未能解决你的问题,请参考以下文章