我正在尝试为我的数据库类证明一个语句。我已经声明使用位图索引,可以在包含仅包含枚举值(如性别)的列的表上比在不使用位图索引时更快地执行WHERE查询。
除此之外,我们试图证明它对包含许多不同的随机值的列的表没有帮助。
我们在Oracle SQLDeveloper中创建了两个表,如上所述填充了上述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秒。我们也尝试删除索引,没有结果。我们是否错过了这里的某些内容,或者我们是否正确地做了所有事情,而你却看不出速度上的差异?
答案 0 :(得分: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个块读取(“一致获取”):
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
答案 1 :(得分:2)
尝试选择较少的行(相对于表中的所有行)。如果查询选择表中的大部分行,Oracle的查询优化器可能(正确地)决定只进行全表扫描实际上更快 - 如果它必须加载表堆的大部分或全部块,它也可以直接做到。
除此之外,您的测试集太小了。尝试一个足够大的组(添加几个零)以将执行时间推到秒表的分辨率之外(在Windows机器上通常为16毫秒)。更好的是,选择一个不完全适合缓存的大小。
但即使你做了所有这些,你仍可能会得到一些奇怪的结果,因为甲骨文的整体“聪明”。例如,Oracle 11g引入了query result cache,它可以完全扭曲重复查询的执行时间。
答案 2 :(得分:1)
答案 3 :(得分:1)
除了拥有足够大的数据集之外,还应查看执行每个查询之前清除缓存的情况