即使没有索引,查询也可能非常快。因此,您无法通过秒表来展示性能提升。
我创建了一个包含 1.000.000 行的测试表。在我们的机器上,没有任何索引的全表扫描需要 0.2 秒。使用位图索引,需要 0.09 秒。但是,没有索引,它会扫描所有 2000 个数据库块,使用位图索引,它需要读取 60-70 个块。
CREATE TABLE indextest (
id NUMBER NOT NULL,
gender VARCHAR2(1) NOT NULL CHECK (gender IN ('M','F')),
married VARCHAR2(1) NOT NULL CHECK (married IN ('Y','N')),
children VARCHAR2(1) NOT NULL CHECK (children IN ('Y','N'))
) NOLOGGING;
INSERT /*+ APPEND */
INTO indextest (id, gender, married, children)
WITH
q1 AS (SELECT level AS x1 FROM dual CONNECT BY level <= 1000),
q2 AS (SELECT 1000*(level-1) AS x2 FROM dual CONNECT BY level <= 1000),
q3 AS (SELECT x2+x1 AS id FROM q1, q2)
SELECT id,
CASE WHEN dbms_random.value < 0.5 THEN 'M' ELSE 'F' END as gender,
CASE WHEN dbms_random.value < 0.3 THEN 'Y' ELSE 'N' END as married,
CASE WHEN dbms_random.value < 0.2 THEN 'Y' ELSE 'N' END as children
FROM q3;
COMMIT;
EXEC DBMS_STATS.GATHER_TABLE_STATS(user, 'indextest');
ALTER TABLE indextest ADD CONSTRAINT pk_indextest PRIMARY KEY (id);
CREATE BITMAP INDEX bi_indextest_gender ON indextest(gender);
CREATE BITMAP INDEX bi_indextest_married ON indextest(married);
CREATE BITMAP INDEX bi_indextest_children ON indextest(children);
现在,如果您显示查询统计信息,例如在 SQL*Plus 中,您可以显示使用索引需要 60-70 个块读取(“一致获取”):
SET TIMING ON
SET LINE 300
SET AUTOTRACE TRACE EXPLAIN STAT
SELECT count(*) FROM indextest WHERE gender = 'M' AND married = 'N' AND children = 'Y';
Abgelaufen: 00:00:00.07
------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 6 | 63 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 6 | | |
| 2 | BITMAP CONVERSION COUNT | | 125K| 732K| 63 (0)| 00:00:01 |
| 3 | BITMAP AND | | | | | |
|* 4 | BITMAP INDEX SINGLE VALUE| BI_INDEXTEST_CHILDREN | | | | |
|* 5 | BITMAP INDEX SINGLE VALUE| BI_INDEXTEST_GENDER | | | | |
|* 6 | BITMAP INDEX SINGLE VALUE| BI_INDEXTEST_MARRIED | | | | |
------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("CHILDREN"='Y')
5 - access("GENDER"='M')
6 - access("MARRIED"='N')
Statistiken
----------------------------------------------------------
0 recursive calls
0 db block gets
67 consistent gets
0 physical reads
0 redo size
235 bytes sent via SQL*Net to client
252 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed
如果隐藏索引,Oracle 需要扫描整个表:
ALTER INDEX bi_indextest_gender INVISIBLE;
ALTER INDEX bi_indextest_married INVISIBLE;
ALTER INDEX bi_indextest_children INVISIBLE;
SELECT count(*) FROM indextest WHERE gender = 'M' AND married = 'N' AND children = 'Y';
Abgelaufen: 00:00:00.15
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 6 | 512 (6)| 00:00:07 |
| 1 | SORT AGGREGATE | | 1 | 6 | | |
|* 2 | TABLE ACCESS FULL| INDEXTEST | 125K| 732K| 512 (6)| 00:00:07 |
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("GENDER"='M' AND "MARRIED"='N' AND "CHILDREN"='Y')
Statistiken
----------------------------------------------------------
292 recursive calls
0 db block gets
2289 consistent gets
0 physical reads
0 redo size
235 bytes sent via SQL*Net to client
252 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
6 sorts (memory)
0 sorts (disk)
1 rows processed