在 SQL 子查询中使用多个表进行 Oracle 半联接
Posted
技术标签:
【中文标题】在 SQL 子查询中使用多个表进行 Oracle 半联接【英文标题】:Oracle semi-join with multiple tables in SQL subquery 【发布时间】:2015-06-03 23:37:29 【问题描述】:这个问题是如何解决在子查询中使用多个表进行半连接时明显的 oracle 限制。我有以下 2 个 UPDATE 语句。
更新 1:
UPDATE
(SELECT a.flag update_column
FROM a, b
WHERE a.id = b.id AND
EXISTS (SELECT NULL
FROM c
WHERE c.id2 = b.id2 AND
c.time BETWEEN start_in AND end_in) AND
EXISTS (SELECT NULL
FROM TABLE(update_in) d
WHERE b.time BETWEEN d.start_time AND d.end_time))
SET update_column = 'F'
执行计划表明这正确执行了 2 个半连接,并且更新在几秒钟内执行。这些需要半连接,因为c.id2
不是b.id2
上的唯一外键,这与b.id
和a.id
不同。而update_in
根本没有任何约束,因为它是一个数组。
更新 2:
UPDATE
(SELECT a.flag update_column
FROM a, b
WHERE a.id = b.id AND
EXISTS (SELECT NULL
FROM c, TABLE(update_in) d
WHERE c.id2 = b.id2 AND
c.time > d.time AND
b.time BETWEEN d.start_time AND d.end_time))
SET update_column = 'F'
这不做半连接;我相信基于 Oracle 文档,这是因为 EXISTS 子查询中有 2 个表。由于表的大小和分区,此更新需要数小时。但是,除了位于同一行之外,无法将 d.time
与关联的 d.start_time
和 d.end_time
相关联。而我们之所以传入update_in
数组并在这里加入它,是因为在循环中针对每个 time/start_time/end_time 组合运行此查询也证明性能很差。
除了 2 个表之外,还有其他原因导致半连接无法正常工作吗?如果没有,有没有办法绕过这个限制?我缺少一些简单的解决方案,可以在不将 2 个表放入子查询的情况下使这些条件起作用?
【问题讨论】:
我怀疑使用数组。我建议不要尝试将数组视为表,而是创建一个全局临时表(具有适当的索引),用update_in
的值填充它,然后在临时表上进行连接。祝你好运。
包含与update_in
相同值的全局临时表仍需要半联接。
【参考方案1】:
正如 Bob 建议的那样,您可以使用与 update_in 数组具有相同结构的全局临时表 (GTT),但主要区别在于您可以在 GTT 上创建索引,并且如果您使用代表性样本数据填充 GTT,您还可以收集有关表的统计信息,以便 SQL 查询分析器能够更好地预测最佳查询计划。
也就是说,您的两个查询中还有一些其他显着差异:
在第一个查询的第一个存在子句中,您引用了两个没有表引用的列 start_in 和 end_in。我的猜测是它们要么是表 a 或 b 中的列,要么是 sql 语句当前范围内的变量。不清楚是哪个。 在您的第二个查询中,您引用了 d.time 列,但是,您在第一个查询中没有使用该列。将您的第二个查询更新为以下内容是否会提高其性能?
UPDATE
(SELECT a.flag update_column
FROM a, b
WHERE a.id = b.id AND
EXISTS (SELECT NULL
FROM c, TABLE(update_in) d
WHERE c.id2 = b.id2 AND
c.time BETWEEN start_in AND end_in AND
c.time > d.time AND
b.time BETWEEN d.start_time AND d.end_time))
SET update_column = 'F'
【讨论】:
不幸的是,这个问题(以及我问的另一个 SQL 问题)很久以前就使用了一些解决方法解决了,我什至不记得也没有时间发布。但是,澄清一下:在第一个查询中, start_in 和 end_in 是存储过程的输入参数(两个查询中的 update_in 也是如此)。在第二个查询中,d.time 类似于第一个查询的 start_in,除了 update_in 中的每一行需要不同的值,与第一个查询不同,第一个查询它们都相同,因此不需要 update_in 中的列。以上是关于在 SQL 子查询中使用多个表进行 Oracle 半联接的主要内容,如果未能解决你的问题,请参考以下文章
Oracle(sql)文盲大扫除思维导图系列——多表连接查询子查询