Oracle 如何用空值索引日期列?
当某些行具有空值时,我应该如何索引日期列? 我们必须在日期范围和日期为空的行之间选择行 我们使用Oracle 9.2及更高版本 我找到的选择Oracle 如何用空值索引日期列?,oracle,optimization,indexing,null,Oracle,Optimization,Indexing,Null,当某些行具有空值时,我应该如何索引日期列? 我们必须在日期范围和日期为空的行之间选择行 我们使用Oracle 9.2及更高版本 我找到的选择 在日期列上使用位图索引 使用日期列上的索引和状态字段上的索引,当日期为空时,该字段的值为1 使用“日期”列上的索引和其他“已授予非空”列 我对这些选择的看法是: to 1:表格必须有许多不同的值才能使用位图索引 to 2:我必须仅为此目的添加一个字段,并在检索空日期行时更改查询 to 3:在索引中添加一个实际上不需要的字段非常棘手 这种情况下的最佳做法是什
to 2:我必须仅为此目的添加一个字段,并在检索空日期行时更改查询
to 3:在索引中添加一个实际上不需要的字段非常棘手
这种情况下的最佳做法是什么? 提前谢谢 我读过一些信息:
编辑 我们的桌子上有30万条记录。每天插入和删除1000到10000条记录。280000条记录在日期具有空值。它是一种拾取缓冲区 我们的结构(翻译成英文)是:
您的意思是您的查询将是这样的吗
select ...
from mytable
where (datecol between :from and :to
or datecol is null);
只有当空值在表中相对较少时,才值得对其进行索引-否则,全表扫描可能是找到它们的最有效方法。假设值得为它们编制索引,您可以创建一个基于函数的索引,如下所示:
create index mytable_fbi on mytable (case when datecol is null then 1 end);
然后将查询更改为:
select ...
from mytable
where (datecol between :from and :to
or case when datecol is null then 1 end = 1);
您可以将箱子包装成一个函数,使其更加光滑:
create or replace function isnull (p_date date) return varchar2
DETERMINISTIC
is
begin
return case when p_date is null then 'Y' end;
end;
/
create index mytable_fbi on mytable (isnull(datecol));
select ...
from mytable
where (datecol between :from and :to
or isnull(datecol) = 'Y');
我确保函数在日期不为NULL时返回NULL,以便索引中只存储NULL日期。我还必须将函数声明为确定性函数。(我把它改为返回“Y”而不是1,只是因为对我来说“isnull”这个名字意味着它应该返回;请随意忽略我的偏好!)除了Tony的建议之外,还有一个选项可以为列编制索引,这样您就不需要调整查询了。诀窍是只在索引中添加一个常量值 示范: 创建一个包含10000行的表,其中只有6行包含a_date列的空值
SQL> create table mytable (id,a_date,filler)
2 as
3 select level
4 , case when level < 9995 then date '1999-12-31' + level end
5 , lpad('*',1000,'*')
6 from dual
7 connect by level <= 10000
8 /
Table created.
720个一致的GET和完整的表扫描
现在更改索引以包括常数1,并重复测试:
SQL> set autotrace off
SQL> drop index i1
2 /
Index dropped.
SQL> create index i1 on mytable (a_date,1)
2 /
Index created.
SQL> exec dbms_stats.gather_table_stats(user,'mytable',cascade=>true)
PL/SQL procedure successfully completed.
SQL> set autotrace on
SQL> select id
2 , a_date
3 from mytable
4 where a_date is null
5 /
ID A_DATE
---------- -------------------
9995
9996
9997
9998
9999
10000
6 rows selected.
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=6 Bytes=72)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'MYTABLE' (Cost=2 Card=6 Bytes=72)
2 1 INDEX (RANGE SCAN) OF 'I1' (NON-UNIQUE) (Cost=2 Card=6)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
6 consistent gets
0 physical reads
0 redo size
285 bytes sent via SQL*Net to client
234 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
6 rows processed
6个一致GET和一个索引范围扫描
问候,,
罗布
“我们的表有300000条记录。。。。
280000条记录具有空值
于年月日交付。”
换句话说,几乎整个表都满足一个查询,该查询搜索传递的位置为null。索引对于该搜索是完全不合适的。全表扫描是最好的方法
如果您有Enterprise Edition许可证,并且有空闲的CPU,则使用并行查询可以减少运行时间。避免表查找,并创建如下索引:
create index i1 on mytable (a_date,id) ;
您好,一行有多少字节,有多少行/增长率是多少?编辑后:如果300000行中有280000行包含空值,并且您希望将它们全部选中,为什么要为空值编制索引?如果你打算阅读整本书,为什么你要按索引阅读一本书?@Alexander:你的问题很重要。正因为如此,我分析了数据,这是我应该首先做的。毕竟你绝对正确(就像罗布在评论中说的那样)。我投票赞成其他人的回答。他们可以在其他情况下提供帮助,起初没有关于数据的信息。@HeinzZ-这是一个非常恰当的观点。数据库都是关于数据的。因此,在性能调整方面,卷和分布(尤其是倾斜分布)是关键信息。B树索引项仅包含非空值。因此,当您仅在a_date列上有一个索引时,该索引包含9994个条目。添加常量会使所有10000行显示在索引中,因此适合用于查询。
SQL> set autotrace off
SQL> drop index i1
2 /
Index dropped.
SQL> create index i1 on mytable (a_date,1)
2 /
Index created.
SQL> exec dbms_stats.gather_table_stats(user,'mytable',cascade=>true)
PL/SQL procedure successfully completed.
SQL> set autotrace on
SQL> select id
2 , a_date
3 from mytable
4 where a_date is null
5 /
ID A_DATE
---------- -------------------
9995
9996
9997
9998
9999
10000
6 rows selected.
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=6 Bytes=72)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'MYTABLE' (Cost=2 Card=6 Bytes=72)
2 1 INDEX (RANGE SCAN) OF 'I1' (NON-UNIQUE) (Cost=2 Card=6)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
6 consistent gets
0 physical reads
0 redo size
285 bytes sent via SQL*Net to client
234 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
6 rows processed
create index i1 on mytable (a_date,id) ;