我正在创建一个复合索引。
create index I on TEST (A,B);
我的查询就像
select * from TEST where A=:1 and B IS NOT NULL
上面的查询只会返回几行(< 10),但是我的主要颜色" A"并不是很独特,可以为一个值返回50万条记录。
现在,如果我运行上面的查询,它会执行太多逻辑读取,因为这将扫描所有具有值A =:1的块。
是否有任何技巧/解决方法来索引部分数据。例如,只有数据将进入B IS NOT NULL的索引。这将使我的索引非常紧凑和quiker。
答案 0 :(得分:1)
是否有任何技巧/解决方法来索引部分数据。例如,只有数据将进入B IS NOT NULL的索引。
你可以这样做with a function-based index。在他们的条件唯一性示例中,它说:
Oracle数据库不会在索引中存储所有键都为NULL的行。
你不是做同样的事情,但可以使用相同的机制:
create index J on TEST (case when B is not null then A end, B);
假设您的表格与您显示的一样简单,并且对于相同的A值有100000行,其中99998个B设置为null,另外两个具有非空值。
create table test (a number not null, b number);
insert into test values (1, 1);
insert into test values (1, 2);
insert into test select 1, null from dual connect by level < 99999;
并创建原始索引和基于函数的索引:
create index I on TEST (A,B);
create index J on TEST (case when B is not null then A end, B);
然后,如果你收集统计数据,你可以看到每个索引中的行数:
select index_name, num_rows from user_indexes where index_name in ('I','J');
INDEX_NAME NUM_ROWS
------------------------------ ----------
I 1000000
J 2
根据执行计划,您的查询使用较小的索引:
var v1 number;
exec :v1 := 1;
set autotrace on
select * from test where a = :v1 and b is not null;
A B
---------- ----------
1 1
1 2
Explain Plan
-----------------------------------------------------------
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------
Plan hash value: 3591688522
------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 10 | 2 (0)| 00:00:01 |
|* 1 | TABLE ACCESS BY INDEX ROWID| TEST | 2 | 10 | 2 (0)| 00:00:01 |
|* 2 | INDEX FULL SCAN | J | 1 | | 1 (0)| 00:00:01 |
------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------
1 - filter("A"=:V1)
2 - filter("B" IS NOT NULL)
Statistics
-----------------------------------------------------------
4 Requests to/from client
4 consistent gets
...
如果我删除J
索引并重复查询,则执行全表扫描并获得1610一致性;您可能会看到I
索引范围扫描或快速全扫描,具体取决于选择性 - 因为我只有一个A值,这与您的方案完全匹配。
答案 1 :(得分:0)
如果您可以使用它,位图索引将对您有所帮助,因为位图索引也会存储 NULL 值。
但请注意,如果表上存在事务负载,您不想使用位图索引,尤其是并发事务。
我的测试用例
create table tt as
select 1 a, 1 b from dual union all
select 1 a, null b from dual connect by level <= 1000000;
create index tt_idx on tt(a,b);
select /*+ INDEX(tt) */ * from tt where a = 1 and b is not NULL;
执行
1105 consistent gets
create bitmap index tt_idx on tt(a,b);
执行
83 consistent gets
或者您可以使用基于函数的索引,但您必须重写查询。
create index tt_idx on tt(a,case when b is not null then 1 end);
必须重新制定查询,以便可以使用索引
select /*+ INDEX(tt) */ * from tt where a = 1 and case when b is not null then 1 end = 1;
执行
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("A"=1 AND CASE WHEN "B" IS NOT NULL THEN 1 END =1)
带
5 consistent gets