1

データベースクラスのステートメントを証明しようとしています。ビットマップ インデックスを使用すると、ビットマップ インデックスを使用しない場合よりも、列挙型の値 (性別など) のみを含むテーブルで WHERE クエリを高速に実行できると述べました。

これに加えて、多数の異なるランダムな値を含む列を持つテーブルでは役に立たないことを証明しようとしています。

上記で説明したように、Oracle SQLDeveloper で 2 つのテーブルを作成し、上記で説明したように 10000 行の情報を入力しました。Oracle のバージョンは v11 です。

テーブルに情報を格納する手順を使用しました。列挙値がランダムに 'S'、'M'、または 'L' に設定されているのに対し、他のテーブルの値は完全にランダムです (数字と文字)。

最初に、次のステートメントを実行しました。

set timing on
SELECT * FROM INDEXTEST2 WHERE GENDER = 'M' AND MARRIED = 'N' AND CHILDREN = 'Y'

このスクリプトを繰り返し実行すると、最終的に 00.016 秒かかりました。この後、テーブルを右クリックしてインデックスを作成し、インデックスを作成しました。すべての列を選択してチェックしBitmapました。その後、クエリを数回再実行しましたが、同じ速度 (約 00.015 秒) に遭遇しました。インデックスの削除も試みましたが、結果はありませんでした。ここで何かを見逃しているのでしょうか、それともすべてを正しく行ったのに速度の違いが見られないのでしょうか?

4

4 に答える 4

2

(テーブル内のすべての行に対して)より少ない行を選択してみてください。クエリがテーブル内の行の大部分を選択する場合、Oracleのクエリオプティマイザは、テーブルヒープのほとんどまたはすべてのブロックをロードする必要がある場合、テーブル全体のスキャンを実行する方が実際には高速であると(正しく)判断する可能性があります。直接行うのもよいでしょう。

それはさておき、テストセットが小さすぎます。ストップウォッチの解像度(通常、Windowsマシンでは16ミリ秒)を超えて実行時間をプッシュするのに十分な大きさのセット(いくつかのゼロを追加)を試してください。さらに良いことに、キャッシュに完全に収まらないサイズを選択してください。

しかし、それをすべて行ったとしても、Oracleの全体的な「賢さ」のために、奇妙な結果が得られる可能性があります。たとえば、Oracle 11gは、繰り返されるクエリの実行時間を完全に歪める可能性のあるクエリ結果キャッシュを導入しました。

于 2013-01-10T17:59:30.253 に答える
2

インデックスがなくても、クエリはおそらく非常に高速です。したがって、ストップウォッチでパフォーマンスの向上を実証することはできません。

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
于 2013-01-10T17:21:26.623 に答える
1
  1. 列ごとに 1 つのビットマップ インデックスを作成します。
  2. 十分な量のデータでテストします。
  3. DBMS_Xplan を使用して実行計画を表示する
于 2013-01-10T14:32:11.237 に答える