㈠ 合作的基础
⑴ /* 全为 NULL 的列是无法存储到B*Tree里面的 */ hr@ORCL> create table t (x number,y number); hr@ORCL> create index idx_t on t(x,y); hr@ORCL> insert into t values(1,1); hr@ORCL> insert into t values(1,null); hr@ORCL> insert into t values(null,1); hr@ORCL> insert into t values(null,null); hr@ORCL> commit; hr@ORCL> exec dbms_stats.gather_table_stats(ownname=>USER,tabname=>'T'); hr@ORCL> exec dbms_stats.gather_index_stats(ownname=>USER,indname=>'IDX_T'); /*插入了4行、而在索引中仅存储了3 行*/ hr@ORCL> select index_name,num_rows from user_indexes where index_name='IDX_T'; INDEX_NAME NUM_ROWS ------------------------------ ---------- IDX_T 3 ⑵ /*只有当索引键中至少有一个列定义为NOT NULL 时查询才会使用索引 */ --走索引 hr@ORCL> drop table t purge; hr@ORCL> create table t (x number,y number not null); hr@ORCL> create unique index idx_t on t(x,y); hr@ORCL> insert into t values(1,1); hr@ORCL> insert into t values(NULL,1); hr@ORCL> exec dbms_stats.gather_table_stats(ownname=>USER,tabname=>'T'); hr@ORCL> exec dbms_stats.gather_index_stats(ownname=>USER,indname=>'IDX_T'); hr@ORCL> set autot trace exp hr@ORCL> select * from t where x IS NULL; Execution Plan ---------------------------------------------------------- Plan hash value: 2296882198 -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 5 | 1 (0)| 00:00:01 | |* 1 | INDEX RANGE SCAN| IDX_T | 1 | 5 | 1 (0)| 00:00:01 | -------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - access("X" IS NULL) --不走索引 hr@ORCL> drop table t purge; hr@ORCL> create table t (x number,y number); hr@ORCL> create unique index idx_t on t(x,y); hr@ORCL> insert into t values(1,1); hr@ORCL> insert into t values(1,null); hr@ORCL> insert into t values(null,1); hr@ORCL> insert into t values(null,null); hr@ORCL> commit; hr@ORCL> exec dbms_stats.gather_table_stats(ownname=>USER,tabname=>'T'); hr@ORCL> exec dbms_stats.gather_index_stats(ownname=>USER,indname=>'IDX_T'); hr@ORCL> set autot trace exp hr@ORCL> select * from t where x IS NULL; Execution Plan ---------------------------------------------------------- Plan hash value: 1601196873 -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 2 | 8 | 3 (0)| 00:00:01 | |* 1 | TABLE ACCESS FULL| T | 2 | 8 | 3 (0)| 00:00:01 | -------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("X" IS NULL)
㈡ 互惠共赢
① 场景
某表、某倾斜列、且只有 2 个可取值
② 需求
● 索引访问少数行
● 全表扫描访问多数行
● 节省索引维护成本、降低索引存储开销
③ 方案
有 2:
● 对多数行使用 NULL、而对少数行使用你希望的任何值
● 使用函数索引、只索引函数的非NULL返回值、这是函数非常好的一个运用
④ 例子
某张工单表t、status列只有处理(1)和未处理(0)两种状态、其中、未处理占:10%、已处理占90%
经常查询未处理的、下面演示这个例子
hr@ORCL> drop table t purge; hr@ORCL> create table t (x number,y number); hr@ORCL> create index idx_t on t (decode(x,0,0,NULL)); hr@ORCL> insert into t values(0,1); hr@ORCL> ed Wrote file afiedt.buf 1 begin 2 for i in 1..1000 3 loop 4 insert into t values(1,i); 5 end loop; 6 commit; 7* end; 8 / PL/SQL procedure successfully completed. hr@ORCL> exec dbms_stats.gather_table_stats(ownname=>USER,tabname=>'T'); hr@ORCL> exec dbms_stats.gather_index_stats(ownname=>USER,indname=>'IDX_T'); /*索引只存储了 1 行、节省了索引存储空间 */ hr@ORCL> select index_name,num_rows from user_indexes where index_name='IDX_T'; INDEX_NAME NUM_ROWS ------------------------------ ---------- IDX_T 1 hr@ORCL> set autot trace exp /* CBO选择走索引*/ hr@ORCL> select * from t where decode(x,0,0,NULL)=0; Execution Plan ---------------------------------------------------------- Plan hash value: 1594971208 ------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 7 | 2 (0)| 00:00:01 | | 1 | TABLE ACCESS BY INDEX ROWID| T | 1 | 7 | 2 (0)| 00:00:01 | |* 2 | INDEX RANGE SCAN | IDX_T | 1 | | 1 (0)| 00:00:01 | ------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access(DECODE("X",0,0,NULL)=0)
By David Lin
2013-06-10
Good Luck
端午节快乐