Oracle OR条件使查询非常慢

Ste*_*ane 3 sql oracle

我有一张表(5000万行),在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        |
-------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)

计划查询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        |
-------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)

计划查询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               |
----------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)

Sam*_*Sam 6

以我的经验,OR倾向于对查询产生负面影响(例如忽略索引和触发全表扫描)。有时候情况还算不错,但是由于这个原因,我的查询从快速减少到花费几分钟。

一种可能的解决方案是将更改为,甚至更改OR为。过去,我在提高查询性能方面已经取得了成功,但是您必须将它们进行相互比较,以了解这是否对您有用。UNIONUNION ALL

您可以尝试以下三个选项,看看它们中的任何一个是否都比其他选项有了显着改进。

原始查询(已修改为返回行,因为您提到返回数据而不是进行计数):

select * from table where column_a in (list_a) or column_b in (list_b)
Run Code Online (Sandbox Code Playgroud)

查询避免OR

select * from table where column_a in (list_a)
UNION
select * from table where column_b in (list_b)
Run Code Online (Sandbox Code Playgroud)

而且由于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)
Run Code Online (Sandbox Code Playgroud)