我有一个表(50M行),其在column_a和column_b
上有索引当我select count(*) from table where column_a in (list_a)
时,我立即得到了结果。
与select count(*) from table where column_b in (list_b)
相同。
但是当我做的时候
select count(*) from table where column_a in (list_a) or column_b in (list_b)
我的查询变得极其缓慢,并在输出正确的数字前半小时......我做错了什么?如何优化此查询的实际行为?
谢谢!
计划查询1:
Plan hash value: 2471097773
-------------------------------------------------------------
| Id | Operation | Name |
-------------------------------------------------------------
| 0 | SELECT STATEMENT | |
| 1 | SORT AGGREGATE | |
| 2 | NESTED LOOPS | |
| 3 | SORT UNIQUE | |
| 4 | TABLE ACCESS FULL | LIST_A |
| 5 | BITMAP CONVERSION COUNT | |
| 6 | BITMAP INDEX SINGLE VALUE| MY_TABLE_IX02 |
-------------------------------------------------------------
计划查询2
Plan hash value: 1870911518
-------------------------------------------------------------
| Id | Operation | Name |
-------------------------------------------------------------
| 0 | SELECT STATEMENT | |
| 1 | SORT AGGREGATE | |
| 2 | NESTED LOOPS | |
| 3 | SORT UNIQUE | |
| 4 | TABLE ACCESS FULL | LIST_B |
| 5 | BITMAP CONVERSION COUNT | |
| 6 | BITMAP INDEX SINGLE VALUE| MY_TABLE_IX05 |
-------------------------------------------------------------
计划查询3:
Plan hash value: 1821967683
----------------------------------------------------------------
| Id | Operation | Name |
----------------------------------------------------------------
| 0 | SELECT STATEMENT | |
| 1 | SORT AGGREGATE | |
| 2 | FILTER | |
| 3 | VIEW | index$_join$_001 |
| 4 | HASH JOIN | |
| 5 | BITMAP CONVERSION TO ROWIDS| |
| 6 | BITMAP INDEX FULL SCAN | MY_TABLE_IX02 |
| 7 | BITMAP CONVERSION TO ROWIDS| |
| 8 | BITMAP INDEX FULL SCAN | MY_TABLE_IX05 |
| 9 | TABLE ACCESS FULL | LIST_A |
| 10 | TABLE ACCESS FULL | LIST_B |
----------------------------------------------------------------
答案 0 :(得分:6)
根据我的经验,OR往往会对查询产生负面影响(比如忽略索引并触发全表扫描)。有时这并不是那么糟糕,但我有一些问题,从快速减轻到花费几分钟就可以了。
一种可能的解决方案是将OR
更改为UNION
甚至UNION ALL
。我过去已经成功地提高了查询的性能,但你必须将它们相互比较,看看这是否适合你。
您可以尝试下面的三个选项,看看其中任何一个选项是否比其他选项提供了显着的改进。
原始查询(编辑后返回行,因为您提到了返回数据而不是进行计数):
select * from table where column_a in (list_a) or column_b in (list_b)
避免OR
:
select * from table where column_a in (list_a)
UNION
select * from table where column_b in (list_b)
由于UNION
会触发DISTINCT
,因此这也值得尝试:
select * from table where column_a in (list_a) and not column_b in (list_b)
UNION ALL
select * from table where column_b in (list_b) and not column_a in (list_a)
UNION ALL
select * from table where column_a in (list_a) and column_b in (list_b)
答案 1 :(得分:0)
我猜Oracle正在使用索引进行前两个查询,并对第三个进行全表扫描。如果你考虑一下,那么Oracle不能将索引用于第三个查询是合乎逻辑的:
但两个索引都不会向Oracle提供有关(column_a,column_b)组合的信息。因此,为了加快查询速度,您需要一个包含column_a和column_b的索引。