我有数百万行 table。出于性能原因,我被告知在子句中使用 union 而不是。是真的吗?

I have million rows in one table. I am tolde to use union instead on in clause for performance reason. is it true?

我们有数百万行 table。

我们的select:

select * from tableA where column1 in ("a", "b", "c", "d") and where column2 = "abc";

并且我们在 column1 和 column2 上组合了唯一索引。

有人告诉我切换到:

select * from tableA where column1 = "a" and column2 = "abc"
union
select * from tableA where column1 = "b" and column2 = "abc"
union
select * from tableA where column1 = "c" and column2 = "abc"
union
select * from tableA where column1 = "d" and column2 = "abc";

我们可以在 IN 子句中有 1 到 100 个不同的值。那么 运行 一条带 IN 子句的语句还是 运行 100 条语句并执行合并更好。

谁让你换的?他们是否提供了一些证据表明第二种方法在您的数据环境中实际上更有效?

除非您的统计数据非常不正确或者有更多的事情发生,否则我认为 UNION 方法不太可能比 IN 方法更有效。如果您要分解查询,使用 UNION ALL 会比使用 UNION 更有效,因为它不会强制进行额外的排序来检查和消除(不存在的)重复行。假设一个相对较新的 Oracle 版本,我希望优化器能够在内部将 UNION ALL 查询重写为 IN.

鉴于您有问题 table,您应该能够评估这两个选项在您的实际环境中的实际性能。您应该能够看到一种方法是否始终优于另一种方法,一种方法的逻辑 I/O 是否不如另一种,等等。您还应该能够确定这两种查询是否实际上生成了不同的计划。如果 UNION ALL 方法更有效,我会强烈考虑查看在您的 table 和索引上收集的统计数据,以确定优化器为何没有找到更有效的计划使用 IN 语句。

如果您在 column1, column2 上有一个唯一索引——按照这个顺序——那么带有 union 的版本肯定会利用该索引。如评论中所述,您应该使用 union all 而不是 union。这消除了删除重复项的步骤(即使有 none)。这将是一些索引查找操作,应该会非常快。

Oracle 是否按要求使用第一个版本的索引有点开放:

where column1 in ('a', 'b', 'c', 'd') and column2 = 'abc'

在这种情况下,大多数数据库不会最佳地使用索引。如果数据库使用索引,它将使用索引进行 column1 查找,然后扫描索引比较值与 column2。 Oracle 可能有一些额外的智能可以在这里有效地使用索引。

但是,解决问题很容易。如果您在 column2, column1 上有一个索引,那么该索引将用于 where 子句。

只是为了提供另一种选择,该语句可以写成:

select * from tableA where (column1 = "a" and column2 = "abc")
or (column1 = "b" and column2 = "abc") 
or (column1 = "c" and column2 = "abc") 
or (column1 = "d" and column2 = "abc") ;