Oracle OR条件使查询非常慢

时间:2015-02-26 12:46:36

标签: sql oracle

我有一个表(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               |
----------------------------------------------------------------

2 个答案:

答案 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不能将索引用于第三个查询是合乎逻辑的:

  • column_a上的索引将为Oracle提供有关column_a
  • 值的信息
  • column_b上的索引将为Oracle提供有关column_b
  • 值的信息

但两个索引都不会向Oracle提供有关(column_a,column_b)组合的信息。因此,为了加快查询速度,您需要一个包含column_a和column_b的索引。