如果我查询所有列,Oracle不使用位图索引

2skhul33  于 2023-10-16  发布在  Oracle
关注(0)|答案(1)|浏览(121)

我为column_x上的表创建了一个位图索引。请记住,列x的基数很低,100,000行数据中只有20个唯一值。
那我问

SELECT * FROM table_1
WHERE column_x = 'xyz'

但是它没有执行索引扫描,而是使用了全表扫描。

| Id  | Operation         | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |              | 53295 |  8483K|  3413   (1)| 00:00:01 |
|   1 |  TABLE ACCESS FULL| EMPLOYEE     | 53295 |  8483K|  3413   (1)| 00:00:01 |
----------------------------------------------------------------------------------

现在,如果我为另一列y添加了索引,那么我使用

SELECT column_x,column_y FROM table_1
WHERE column_x = 'xyz'

其结果将是

--------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name             | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |                  | 53295 |   676K|     8  (75)| 00:00:01 |
|*  1 |  VIEW                         | index$_join$_001 | 53295 |   676K|     8  (75)| 00:00:01 |
|*  2 |   HASH JOIN                   |                  |       |       |            |          |
|   3 |    BITMAP CONVERSION TO ROWIDS|                  | 53295 |   676K|     1   (0)| 00:00:01 |
|*  4 |     BITMAP INDEX SINGLE VALUE | DIVISION_IDX     |       |       |            |          |
|   5 |    BITMAP CONVERSION TO ROWIDS|                  | 53295 |   676K|     1   (0)| 00:00:01 |
|   6 |     BITMAP INDEX FULL SCAN    | STATUS_IDX       |       |       |            |          |
--------------------------------------------------------------------------------------------------

为什么不能选择所有列?我不可能为每一列都创建一个索引,对吧?因为有些列具有很高的基数,或者不太符合 where 条件。而且我的查询只返回了所有数据的5%。
我做错什么了吗?

rdlzhqv9

rdlzhqv91#

你没做错什么甲骨文正在做正确的事情。索引并不总是让事情变得更好。Oracle试图变得智能化,只在索引有用的时候使用索引,而不是在索引没用的时候。
当您选择 * 所有 * 列时,获取这些列的唯一方法是从表本身获取。如果它要使用索引来访问基于 predicate (WHERE子句)的数据,那么它将对索引中找到的每个ROWID执行一次单块读取,这将是大约5%的行(1/20),这是非常重要的。那么多低效的单块读取(如果不考虑缓存,这意味着每行都要进行整个I/O操作!)将真正加起来,并使这是一个昂贵的操作在高容量。全表扫描可以比索引访问快5%的速度读取表,因为它使用了更有效的I/O方法,这些方法针对大量数据进行了优化。
当您只选择 * 一个 * 列 *,而该列恰好也被索引 * 时,Oracle可以满足您的整个查询,而根本不使用表。它使用一个索引进行选择,另一个索引用于获取所需的列,并在它们的公共键(ROWID)上将这两个索引相交。根本不需要访问表,因此它不需要执行所有这些单块读取。因此,它发现在这种情况下使用位图索引更可取。
你不应该试图强迫Oracle对所有事情都使用索引。当它认为这是更好的路径时,让它使用全表扫描。通常,全表扫描是正确的选择。有时它会出错,需要轻推(通常通过暗示),但大多数时候你可以让它做它的事情。只有当SQL在运行时实际上执行得不可接受时,才需要投入时间进行性能调优。

相关问题