Oracle如何避免合并笛卡尔加入执行计划



以下查询有时会导致合并的笛卡尔加入执行计划,我们正在尝试重写查询(以最简单的方式),以确保合并笛卡尔加入将会不再发生。

SELECT COL1 
FROM SCHEMA.VIEW_NAME1 
WHERE DATE_VAL > (SELECT DATE_VAL FROM SCHEMA.VIEW_NAME2)

回顾了一个类似的问题:"为什么此查询会导致合并的笛卡尔加入Oracle",该问题似乎是 oracle不知道(从schema.view_name2中选择date_val)返回一个结果。因此,它假设它将产生很多行。"

有没有办法告诉Oracle Optimizer,子选择只会返回一行?

将使用返回日期时间值代替子选择帮助的函数,假设优化器将知道该函数只能返回一个值?

SELECT COL1 
FROM SCHEMA.VIEW_NAME1
WHERE DATE_VAL > SCHEMA.FN_GET_DATE_VAL()

推荐使用wand语句的Oracle DBA,这似乎会起作用,但是我们想知道是否有任何较短的选项。

with mx_dt as (SELECT DATE_VAL FROM SCHEMA.VIEW_NAME2)
SELECT COL1
FROM SCHEMA.VIEW_NAME1, mx_dt a
WHERE DATE_VAL > a.DATE_VAL

尝试添加 WHERE ROWNUM >= 1

SELECT COL1 
FROM SCHEMA.VIEW_NAME1 
WHERE DATE_VAL > (SELECT DATE_VAL FROM SCHEMA.VIEW_NAME2 WHERE ROWNUM >= 1)

谓词看起来完全无关,或者甲骨文只是忽略的东西,但是ROWNUM伪功能是特殊的。当Oracle看到它时,它认为"必须按顺序返回这些行,我最好不要进行任何查询转换"。这意味着它不会尝试推动谓词,合并视图等。这意味着View_name1将与view_name2分开运行,现在它们都与以前一样快。

您可能仍然会在解释计划中看到笛卡尔产品,但希望仅在两个视图结果集之间的顶部附近。如果实际上只有一排返回,那么笛卡尔产品可能是正确的操作。

我不会担心笛卡尔加入,因为该子查询仅返回一行(最多)。否则,您将获得"子查询返回太多行"错误。

Oracle可能会运行每个比较的子查询一次 - 但Oracle Optimizer很聪明,我怀疑这会发生。但是,很容易将其称为JOIN

SELECT n1.COL1 
FROM SCHEMA.VIEW_NAME1 n1 JOIN
     SCHEMA.VIEW_NAME2 n2
     ON n1.DATE_VAL > n2.DATE_VAL;

但是,此执行计划可能更糟,因为您尚未指定n2仅应该返回(最多)一个值。

子选择中的一个聚集功能可确保返回单行。可能是优化器的好提示,如果VIEW_NAME2中只有1行,则子选择的结果是相同的。

SELECT COL1 
  FROM SCHEMA.VIEW_NAME1 
  WHERE DATE_VAL > (SELECT MIN(DATE_VAL) FROM SCHEMA.VIEW_NAME2)

相关内容

  • 没有找到相关文章

最新更新