インデックスがなくても、クエリはおそらく非常に高速です。したがって、ストップウォッチでパフォーマンスの向上を実証することはできません。
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 ブロックの読み取り ("consistent gets") が必要になることがわかります。
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