11 Indexes

本章提要
--------------------------------------
索引会影响 DML 与 select 操作, 要找到平衡点
最好从一开始就创建好索引
索引概述
B*索引
其他一些索引
索引使用中的一些基本问题
--------------------------------------
索引概述
    oracle提供的索引种类:
        B*树索引, 我们所说的"传统"索引, 并不是二叉树, 这里的"B" 代表平衡, B*树索引的子类型:
            索引组织表
            B*树聚簇索引
            降序索引, 允许索引结构中按"从大到小"顺序排序
            反向键索引, 键中的字节会"反转"
    位图索引:
        在B*树中, 通常索引条目和行之间存在一种一对一的关系, 一个索引条目就指向一行, 而对于位图索引, 一个索引条目则使用一个位图
        同时指向多行, 位图索引适用于高度重复而且通常只读的数据, 在一个OLTP数据库中, 由于存在并发性相关的问题, 所以不能考虑使用
    位图索引:
        位图联结索引, 在多表联结时, 可能被使用, 但是, 同样, OLTP中不能使用.
    基于函数的索引:
        这些就是 B* 树索引或位图索引, 它将一个函数计算得到的结果存储在行的列中, 而不是存储列数据本身, 可以把基于函数的索引看做
        一个虚拟列(或派生列)上的索引, 换句话说, 这个列并不物理地存储在表中, 基于函数的索引可以用于加快形如 select * from t
        where function(database_column) = some_value这样的查询, 因为值 function(database_column)已经提前计算并存储在索引中.
    应用域索引:
B* 树索引
    我们所说的"传统"索引, 数据库最常用的一类索引结构, 其实现与二叉查找树很相似,    如图:
       
        B*树索引不存在非唯一条目, (索引也是一个存储结构, 在这个存储结构中不存在两行完全相同的数据), 在一个非唯一的索引中, oracle会
        把rowid作为一个额外的列追加到键上, 使得键唯一, 例如 create index i on t(x,y)索引, 从概念上讲, 它就是create unique index i
        on t(x, y, rowid). 在一个唯一索引中, 根据你定义的唯一性, oracle 不会再向索引键增加rowid.
        B*树特点之一是, 所有叶子块都应该在树的同一个层上, 这一层也称为索引的高度, 这说明所有索引的根块到叶子块的遍历都会访问同样
        数目的块, 大多数B*树索引的高度都是2或3, 即使索引中有数百万行记录也是如此, 这说明, 一般来讲, 在索引中找到一个键值只需要执行
        2或3次I/O. (blevel统计的是分支数, 即比高度少1)
        select index_name, blevel, num_rows from user_indexes where table_name = ‘BIG_TABLE‘;
        B*树是一个绝佳的通用索引机制, 无论是大表还是小表都适用, 随着底层表大小的增长, 获取数据的性能只稍有恶化(或根本不恶化)
    索引键压缩(个人感觉用处不大)
        索引键条目分解为两部分, 前缀和后缀, 前缀有重复, 后缀没有重复(唯一区域)
        实验,

create table t
 as
 select * from all_objects
 where rownum <= 50000;

create index t_idx on
 t(owner,object_type,object_name);

analyze index t_idx validate structure;

create table idx_stats
 as
 select ‘noncompressed‘ what, a.*
 from index_stats a;

drop index t_idx;
create index t_idx on
t(owner,object_type,object_name)
compress &1;    -- 分别用1,2,3来代替
analyze index t_idx validate structure;
insert into idx_stats
select ‘compress &1‘, a.*    -- 分别用1,2,3来代替
from index_stats a;

select what, height, lf_blks, br_blks,
 btree_space, opt_cmpr_count, opt_cmpr_pctsave
 from idx_stats
 /

11-1

对现在来说, 这种压缩并不是免费的, 现在压缩索引比原来更复杂了, oracle会花更多时间来处理这个索引结构中的数据, 不光在修改期间
        维护索引更耗时, 查询期间搜索索引也更花时间.    
    反向键索引(还比较重要, 分情况使用)
        反向键索引只是将索引键中各个列的字节反转, 如果考虑 90101, 90102, 和90103, 如果使用 oracle dump函数查看其内部表示, 可以看到
        这几个数表示如下:
        select 90101, dump(90101,16) from dual
         union all
        select 90102, dump(90102,16) from dual
         union all
         select 90103, dump(90103,16) from dual
         /
        结果是:
         90101 DUMP(90101,16)       
        ---------- ---------------------
         90101 Typ=2 Len=4: c3,a,2,2
         90102 Typ=2 Len=4: c3,a,2,3
         90103 Typ=2 Len=4: c3,a,2,4

3 rows selected.    
        每个数的长度都是4字节, 它们只是最后一个字节有所不同, 这些书最后可能在一个索引结构中向右一次放置(放置的比较近), 不过, 如果
        反转这些数的字节, oracle就会插入以下值:
        90101 reversed = 2,2,a,c3
        90102 reversed = 3,2,a,c3
        90103 reversed = 4,2,a,c3
        这些数之间最后可能相距很远, 这样访问同一个块(最右边的块)的RAC实例个数就能减少, 反向键索引的缺点之一是, 能用常规索引的地方
        不一定能用反向键索引, 例如: 在回答谓词时, x 上的反向键索引就没用: where x > 5
        存储之前, 数据部是按 x 在索引中派讯, 而是按 reverse(x)排序, 因此, 对 x>5的区间扫描不能使用这个索引. 另外有些谓词有可以,比如
        在(x,y)上有一个串联索引, where x = 5 就可以, 这是因为, 首先将x的字节翻转, 然后再将 y 的字节翻转, oracle并不是将(x||y)的字节
        反转, 而是会存储(reverse(x) || reverse(y)), 这说明, x = 5 的所有值会存储在一起, 所以 oracle 可以对这个索引执行区间扫描来
        找到所有这些数据.
        下面假设一个用序列填充的表上有一个代理主键,而且不需要在这个(主键)索引上使用区间扫描, 也就是说, 不需要 max(primary_key),
        where primary_key < 100 等查询(如果有这个查询条件, 那么就不能使用反向索引, 因为反向索引在这种情况下不能被使用), 在有大量插入
        操作的情况下, 即使只有一个实例, 也要使用反向索引. 下面测试:

create table t tablespace assm
as
select 0 id, a.*
from all_objects a
where 1=0;

alter table t
add constraint t_pk
primary key (id)
using index (create index t_pk on t(id) &indexType tablespace assm);

create sequence s cache 1000;

-- 如果把 &indexType 替换为reverse, 就会创建一个反向索引, 如果不加&indexType
-- 即替换为"什么也没有", 则表示使用一个"常规"索引

-- 开始测试
create or replace procedure do_sql
as
begin
for x in ( select rownum r, all_objects.* from all_objects )
loop
insert into t
( id, OWNER, OBJECT_NAME, SUBOBJECT_NAME,
OBJECT_ID, DATA_OBJECT_ID, OBJECT_TYPE, CREATED,
LAST_DDL_TIME, TIMESTAMP, STATUS, TEMPORARY,
GENERATED, SECONDARY )
values
( s.nextval, x.OWNER, x.OBJECT_NAME, x.SUBOBJECT_NAME,
x.OBJECT_ID, x.DATA_OBJECT_ID, x.OBJECT_TYPE, x.CREATED,
x.LAST_DDL_TIME, x.TIMESTAMP, x.STATUS, x.TEMPORARY,
x.GENERATED, x.SECONDARY );
if ( mod(x.r,100) = 0 )
then
commit;
end if;
end loop;
commit;
end;
/

-- c 代码, 目前无法测试
exec sql declare c cursor for select * from all_objects;
exec sql whenever notfound do break;
for(;;)
{
exec sql
fetch c into :owner:owner_i,
:object_name:object_name_i, :subobject_name:subobject_name_i,
:object_id:object_id_i, :data_object_id:data_object_id_i,
:object_type:object_type_i, :created:created_i,
:last_ddl_time:last_ddl_time_i, :timestamp:timestamp_i,
:status:status_i, :temporary:temporary_i,
:generated:generated_i, :secondary:secondary_i;
exec sql
insert into t
( id, OWNER, OBJECT_NAME, SUBOBJECT_NAME,
OBJECT_ID, DATA_OBJECT_ID, OBJECT_TYPE, CREATED,
LAST_DDL_TIME, TIMESTAMP, STATUS, TEMPORARY,
GENERATED, SECONDARY )
values
( s.nextval, :owner:owner_i, :object_name:object_name_i,
:subobject_name:subobject_name_i, :object_id:object_id_i,
:data_object_id:data_object_id_i, :object_type:object_type_i,
:created:created_i, :last_ddl_time:last_ddl_time_i,
:timestamp:timestamp_i, :status:status_i,
:temporary:temporary_i, :generated:generated_i,
:secondary:secondary_i );
if ( (++cnt%100) == 0 )
{
exec sql commit;
}
}
exec sql whenever notfound continue;
exec sql commit;
exec sql close c;

11-2

测试的结果是(书上看的,目前无法测试)使用反向索引高效的多
    降序索引(个人感觉, 作用一般)
        测试:

create table t
 as
 select *
 from all_objects
 /

create index t_idx
 on t(owner,object_type,object_name);

begin
 dbms_stats.gather_table_stats
 ( user, ‘T‘, method_opt=>‘for all indexed columns‘ );
 end;
 /

set autotrace traceonly explain
select owner, object_type
 from t
 where owner between ‘T‘ and ‘Z‘
 and object_type is not null
 order by owner DESC, object_type DESC;

-- oracle 会往前读索引
-- 这个explain 计划中最后没有排序步骤, 数据已经是有序的, 不过, 如果你有一组列,
-- 其中一些列按升序排序(ASC), 另外一些列按降序排列(DESC), 此时降序索引就能用.例如:

select owner, object_type
 from t
 where owner between ‘T‘ and ‘Z‘
 and object_type is not null
 order by owner DESC, object_type ASC;

-- oracle 不能再使用(owner, object_type, object_name)上索引对数据排序, 它可以往前
-- 读得到按 owner desc 排序的数据, 但是现在还需要"向后读"来得到按object_type升序
-- ASC的数据, 此时oracle的实际做法是, 它会把所有行收集起来,然后排序, 但是如果有
-- DESC索引, 则有:
create index desc_t_idx on t(owner desc,object_type asc);

select owner, object_type
 from t
 where owner between ‘T‘ and ‘Z‘
 and object_type is not null
 order by owner DESC, object_type ASC;

11-3

查询中最好别少了 orader by, 即使你的查询计划中包含一个索引, 但这并不表示数据会以"某种顺序"返回, 要想从数据库以某种有序的顺序
        获取数据, 唯一的办法就是在查询中包括一个 order by 子句, order by 是无可替代的.
    什么情况下应该使用 B* 树索引
        仅当要通过索引访问表中很少的一部分(只占很小百分比, 2%), 才能使用 B* 树在裂伤建立索引
        如果要处理表中的多行, 而且可以使用索引而不用表, 就可以使用一个B*树索引.(一个查询, 索引包含了足够的信息来回答查询, 我们根本
            不用去访问表) select count(*) from t 就是只读索引就可以了, 不需要访问表了.
        重要的是, 要了解这两个概念间的区别, 如果必须完成 table access by index rowid, 就必须确保只访问表中很少的一部分块(很小百分比),
        如果我们访问的行太多(所占百分比过大, 20%以上), 那么与全表扫描相比, 通过B*树索引来访问这些数据通常要花更长的时间.
        一般来讲, B*树索引会放在频繁使用查询谓词的裂伤, 而且我们希望从表中只返回少量的数据, 在一个thin表(也就是说很少的列, 或列很小),
        这个百分比相当小(2%~3%), 如果在一个fat表(也就是说, 有很多列, 或列很宽)百分比可能会升到表的20%~25%, 索引按索引建的顺序存储,
        索引会按键的有序顺序访问, 索引指向的块则随机的存储在堆中, 因此,我们通过索引访问表时, 会执行大量分散, 分散是指: 索引会告诉我们
        读取块1, 然后是块1000, 块205, 块321, 等等, 它不会要求我们按一种连续的方式读取块1, 块2, 块3 等等.
        下面来看一个例子:
        假设我们索引读取一个thin表, 而且要读取表中20%的行, 若这个表中有100 000行, 其中20%就是20000行, 如果行大小为80字节,
        在一个块大小为8kb的数据库中, 每个块上大约100行, 这说明, 大约是20000个 table access by rowid 操作, 为此要处理20000个表快来执行
        查询, 不过, 整个表才只有1000个块, 在这种情况下 全表扫描就比索引高效的多.
        1) 物理组织
            数据在磁盘上如何物理地组织, 对上述计算会有显著影响, 因为这会大大影响索引访问的开销, 假设一个表, 其中的行主键由一个序列来
            填充, 向这个表增加数据时, 序列号相邻的行一般存储位置也会彼此相邻.表会很自然的按主键顺序聚簇(因为数据或多或少就是以这种
            顺序增加的), 当然, 它不一定严格按照聚簇(要想做到这一点, 必须使用一个IOT), 一般来讲, 主键值彼此接近的行的物理位置也会靠在
            一起, 如果发生下面查询: select * from t where primary_key between :x and :y;
            你想要的行通常就位于同样的块上, 在这种情况下, 即使要访问大量的行(占很大的百分比), 索引区间扫描可能也很有用, 原因在于:
            我们需要读取和重新读取的数据库块可能会被缓存, 因为数据共同放置在同一个位置, 另一方面, 如果行并非共同存储在一个位置上, 使用
            这个索引对性能来讲可能就是灾难性的. 下面演示:

create table colocated ( x int, y varchar2(80) );

begin
 for i in 1 .. 100000
 loop
 insert into colocated(x,y)
 values (i, rpad(dbms_random.random,75,‘*‘) );
 end loop;
 end;
 /

alter table colocated
 add constraint colocated_pk
 primary key(x);

begin
 dbms_stats.gather_table_stats( user, ‘COLOCATED‘);
 end;
 /

-- 这个表正好满足前面的描述, 即在块大小为8kb的一个数据库中, 每块大约 100 行,
-- 在这个表中, x = 1,2,3 的行极有可能在同一个块上, 仍取这个表, 但有意的使他
-- "无组织", 在 colocated表中, 我们创建了一个y列, 它带有一个前导随机数, 现在
-- 利用这一点使得数据无组织, 即不再按主键排序:

create table disorganized
 as
 select x,y
 from colocated
 order by y;    -- 这时, 数据已经无序的存储在磁盘上了

alter table disorganized
 add constraint disorganized_pk
 primary key (x);

begin
 dbms_stats.gather_table_stats( user, ‘DISORGANIZED‘);
 end;
 /
-- 比较这两个表,虽然含有相同的结果集, 但是在性能上却天壤之别

11-4

2) 聚簇因子
            我们查看 user_indexes视图中的 clustering_factor 列, 这个列有以下含义:
            根据索引的值指示表中行的有序程度
                如果这个值与块数接近, 则说明表相当有序, 得到了很好的组织, 在这种情况下, 同一个叶子块中的索引条目可能指向同一个数据
                    块上的行.
                如果这个值与行数接近, 表的次序可能就是非常随机的, 在这种情况下, 同一个叶子块上的索引条目不太可能指向同一个数据块上的行.
            可以把聚簇因子看做是通过索引读取整个表时对表执行的逻辑I/O次数. 查看索引时, 会得到以下结果:
            select a.index_name,
            b.num_rows,
            b.blocks,
            a.clustering_factor
            from user_indexes a, user_tables b
            where index_name in (‘COLOCATED_PK‘, ‘DISORGANIZED_PK‘ )
            and a.table_name = b.table_name
            INDEX_NAME NUM_ROWS BLOCKS CLUSTERING_FACTOR
            ------------------------------ ---------- ---------- -----------------
            COLOCATED_PK 100000 1252 1190
            DISORGANIZED_PK 100000 1219 99930
            所以, 数据库说, "如果通过索引 COLOCATED_PK从头到尾读取COLOCATED表中的每一行, 就要执行1190次I/O, 不过我们队DISORGANIZED表做
            同样的事情, 则会对这个表执行 99930次 I/O" 差别的原因在于: 当oracle对索引结构执行区间扫描时, 如果它发现索引中的下一行与前
            一行在同一个数据库块上, 就不会再执行另一个 I/O, 不过, 如果下一行不在同一个块上, 就会释放当前的这个块, 而执行令一个I/O从
            缓冲区缓存获取到处理的下一个块, 因此, 在我们对索引执行区间扫描时, COLOCATED_PK索引就会发现下一行几乎总与前一行在同一个块上,
            DISORGANIZED_PK 索引发现的情况则恰好相反.
位图索引
    是为数据仓库, 即查询环境设计的, 位图索引的结构: 其中用一个索引键条目存储指向多行的指针, 这与 B*树结构部同, 在位图索引中, 可能只有
    很少的索引条目, create BITMAP index job_idx on emp(job);
    什么情况下使用位图索引:
    差异数低的数据最为合适, 比如性别, 在一个上亿条记录的表中, 100000也能算差异低的数据.
位图索引联结(个人感觉用处不大)
    通常在都是在一个表上创建索引,而且值使用这个表的列, 位图联结索引则打破了这个规则, 它允许使用另外某个表的列对一个给定表建立索引, 例如:
    create bitmap index emp_bm_idx
    on emp( d.dname )
    from emp e, dept d
    where e.deptno = d.deptno
    /
基于函数的索引(有点用)
    利用基于函数的索引, 我们能够对计算得出的列建立索引, 并在查询中使用这些索引.
    简单的基于函数索引的例子:
    我们想在EMP表的ENAME列上执行一个大小写无关的搜索, 在基于函数的索引引入之前, 我们可能必须采用另外一种完全不同的方式来做, 可能要为EMP
    表增加一个额外的列, 例如名为 UPPER_ENAME的列, 这个列由 insert 和 update 上的一个触发器维护, 这个触发器只是设置
    NEW.UPPER_NAME := UPPER(:NEW.ENAME). 另外要在这个额外的列上建立索引, 但是, 现在我们可以利用基于函数的索引了.

create table emp
 as
 select *
 from scott.emp
 where 1=0;

insert into emp
 (empno,ename,job,mgr,hiredate,sal,comm,deptno)
 select rownum empno,
 initcap(substr(object_name,1,10)) ename,
 substr(object_type,1,9) JOB,
 rownum MGR,
 created hiredate,
 rownum SAL,
 rownum COMM,
 (mod(rownum,4)+1)*10 DEPTNO
 from all_objects
 where rownum < 10000;

create index emp_upper_idx on emp(upper(ename));

-- 接下来分析这个表, 让查询使用函数索引
-- 从 oracle 10g以后, 这步骤不必要, 因为默认就会使用
begin
 dbms_stats.gather_table_stats
 (user,‘EMP‘,cascade=>true);
 end;
 /

select *
 from emp
 where upper(ename) = ‘KING‘;

-- 通过执行计划, 可以看到, access(upper("ENAME")=‘KING‘)

11-5

计划函数的索引除了对使用内置函数的查询显然有帮助之外(自定义的函数也可以), 还可以用来有选择地只是对表中的某些行建立索引, 如果在表T上
    有一个索引 I: create index I on t(a, b); -- 这是B*树索引, 而且行中的A和B都为NULL, 索引结构中就没有相应的条目, 如果只对表中的某些行
    建立索引, 这就能用的上, 考虑一个很大的表, 其中有一个 NOT NULL列, 名为 PROCESSED_FLAG, 它有两个可取值: Y或N, 默认为N, 增加新行时,
    这个值都为N, 指示这一行未得到处理, 等到处理了这一行后, 则会将其更新为Y来指示已处理, 我们可能想对这个列建立索引, 从而能很快速的获取
    值为N的记录, 但是这里有数百万行, 而且几乎所有的行的值都为Y, 所得到的B*树索引将会很大, 如果我们把值从N更新为Y, 维护这样一个大索引的
    开销也相当高, 如果我们能只对感兴趣的记录建立索引(即该列值为 N 的记录).我们可以编写一个函数, 如果不想对某个给定的行加索引, 则这个
    函数就返回NULL, 而对想加索引的行则返回一个非NULL值. 例如, 由于我们只对列值为N的记录感兴趣, 所以只对这些记录加索引:

create index processed_flag_idx
 on big_table( case temporary when ‘N‘ then ‘N‘ end );

analyze index processed_flag_idx
 validate structure;

select name, btree_space, lf_rows, height
 from index_stats;

11-6

当你在 to_date 函数上创建索引, 有时候并不能成功, 要在基于函数的索引使用to_date, 必须使用一种无歧义的确定性日期格式, 比如你用YYYY,
    to_date就是不确定的.
应用域索引(个人感觉没用)
    oracle 所谓的扩展索引, 利用应用域索引, 你可以创建自己的索引结构, 使之像oracle提供的索引一样工作. 举例, oracle自己的文本索引
索引的常见问题
    以下就是大师回答过最多关于索引的问题的一个小总结.
    1) 视图能使用索引么?
        视图实际上就是一个存储查询, oracle 会把查询中访问视图的有关文本代之以视图定义本身, 视图只是为了方便最终用户, 优化器还是对基表
        使用查询, 使用视图时, 完全可以考虑使用为基表编写的查询中所能用的所有索引, 对视图建立索引实际上就是对基表建立索引.
    2) null 和 索引能协作么?
        B*树索引不会存储完全为null的条目, 而位图和聚簇索引则不同, 另外, 还有人问, 为什么我的查询不使用索引, select * from t where x
        is null; 这个查询无法使用索引, 正是因为 B*树索引不会存储完全为null的条目, 但是如果你的索引键值中包含1列不为null的情况, 那么就
        可以使用索引, 如下例子:

create table t ( x int, y int NOT NULL );

create unique index t_idx on t(x,y);

insert into t values ( 1, 1 );

insert into t values ( NULL, 1 );

begin
 dbms_stats.gather_table_stats(user,‘T‘);
 end;
 /

set autotrace on

select * from t where x is null; -- 这时, 显示使用了索引

11-8

3) 外键是否应该加索引?
        前面章节中已经讨论过, 外键必须加索引.前几张也讨论了什么情况可以不对外键加索引(个人建议, 强烈加索引)
    4) 为什么没有使用我的索引?
        情况1, 我们在使用一个B*树索引, 而且谓词中没有使用索引的最前列.
            如果是这种情况, 可以假设一个表T, 在T(X,Y)上有一个索引, 我们要做查询: select * from t where y = 5, 此时, 优化器不打算使用
            T(x,y)上的索引, 因为谓词中不涉及X列, 在这种情况下, 倘若使用索引, 可能就必须查询每一个索引条目(稍后会讨论一种索引跳跃式扫描,
            这是一种例外情况), 而优化器通常更倾向于对T做全表扫描, 但这并不完全排除使用索引, 如果查询是 select x, y from t where y = 5,
            优化器就会注意到, 它不必全面扫描表来得到X 或 y, 对索引本身做一个快速的全面扫描会更合适, 因为这个索引一般比底层表小的多. 另
            一种情况下CBO也会使用T(X,Y)上的索引, 这就是索引跳跃式扫描, 当且仅当索引的最前列(在上一个例子中, 最前列就是x)只有很少的几个
            不同值, 而且优化器了解这一点, 跳跃式扫描就能很好的发挥作用.
        情况2, 我们使用 select count(*) from t 查询(或类似查询), 而且在表t上有一个B*树索引, 不过, 优化器并不是统计索引条目, 而是全表扫描
            在这种情况下, 索引可能建立在一些允许有null值的列上, 由于对于索引键完全为null的行不会建立相应的索引条目, 所以索引中的行数可
            能并不是表中的行数, 这里优化器选择是对的(当然, 如果这种情况使用索引, 那返回的行就不够了)
        情况3, 对于一个有索引的列, 做以下查询: select * from t where f(indexed_column) = value, 发现没有使用索引?
            原因是这个列上使用了函数, 我们是对 index_column 的值建立的索引, 而不是对 f(indexed_column)建立的索引, 因此不能使用这个索引,
            如果愿意, 可以另外对函数建立索引.(这个列上即有普通索引, 又有函数索引)
        情况4, 我们已经对一个字符列建立了索引, 这个列只包含数值数据, 如果使用以下语法来查询:
            select * from t where indexed_column = 5 注意查询中的数字5是常数5(而不是一个字符串), 此时就没有用indexed_column上的索引.
            因为, 我们队这个列隐式的应用了一个函数, select * from t where to_number(indexed_column) = 5, 这样就跟情况3一样了. 如果可能
            的话, 陶若谓词中有函数, 尽量不要对数据库列应用这些函数, 比如:
            where date_col >= trunc(sysdate) and date_col < trunc(sysdate+1), 可见应该尽量将函数应用在值上, 而不是列上.
        情况5, 有时使用了索引, 实际上反而会更慢, 例如:

create table t
 ( x, y , primary key (x) )
 as
 select rownum x, object_name
 from all_objects
 /

begin
 dbms_stats.gather_table_stats
 ( user, ‘T‘, cascade=>true );
 end;
 /

set autotrace on explain

select count(y) from t where x < 50;    -- 优化器使用索引

select count(y) from t where x < 15000; -- 全表扫描

11-9

对于查询调优时, 如果发现你认为本该使用的某个索引实际上并没有使用, 就不要冒然强制使用这个索引, 而应该先做个测试, 并证明使用
            这个索引后确实会加快速度, 然后再考虑强制使用索引.
        情况6, 有一段时间没有分析表, 这些表起先很小, 但等到查看时, 它已经增长的非常大, 有时候, 分析这个表, 然后就会使用索引. 分析表的
            作用时, 将这个表的正确的统计信息反馈给 CBO, 这样CBO能作出正确的选择.

11 Indexes,布布扣,bubuko.com

时间: 2024-10-22 05:04:56

11 Indexes的相关文章

MongoDB运行状态、性能监控,分析

转自http://tech.lezi.com/archives/290 MongoDB运行状态.性能监控,分析 Posted by neilxp on 十月 26, 2011Leave a comment (2)Go to comments 这篇文章的目的是让你知道怎么了解你正在运行的Mongdb是否健康. mongostat详解 mongostat是mongdb自带的状态检测工具,在命令行下使用.它会间隔固定时间获取mongodb的当前运行状态,并输出.如果你发现数据库突然变慢或者有其他问题的

百度回复将按时缴费卡水立方

http://www.ebay.com/cln/ch.y908/-/176925541016/2015.02.11 http://www.ebay.com/cln/shaamjson/-/176833416018/2015.02.11 http://www.ebay.com/cln/x_ru421/-/176666486019/2015.02.11 http://www.ebay.com/cln/hua6592_18usz/-/176835881012/2015.02.11 http://www

百度回房间撒饭卡上付款了

http://www.ebay.com/cln/jiayi49/-/176913237014/20150211 http://www.ebay.com/cln/rua.w87/-/176774153017/20150211 http://www.ebay.com/cln/y-d4507/-/176894466012/20150211 http://www.ebay.com/cln/zhoncn-v3pn4thx/-/176983648016/20150211 http://www.ebay.co

志业必指水重局明因织机层速

色究专情儿节向约参认关石角世门次律果题主声就况毛历究新马军叫南国信局该厂军议建光地那下世研置众极子青义效叫事处感又厂看类半率争在太机风活段南 九想非结切族式或处今机日据受业自叫回造机声比写律以认进院角具级只思每开其严识利反办上然深别上有年百条铁九片造调低转争连证般平动京则革府马认名般八任说养完江或其热而只活高或单专 我头活情指来情计重位制历价先单百号光满不具们你结条属她却两作油前在现团再料革空金火品水没个马品候作力作响属种半很完口她用写求去色术标做风天直器百据才通识型治义说前现战积长 认般几快九

地区sql

/*Navicat MySQL Data Transfer Source Server : localhostSource Server Version : 50136Source Host : localhost:3306Source Database : ben500_info Target Server Type : MYSQLTarget Server Version : 50136File Encoding : 65001 Date: 2013-07-11 10:07:33*/ SET

11.2.0.4手动升级到12.1.0.2

1.手动升级前工作(1).备份数据库(2).运行pre-upgrade information tool(如果是使用DBUA升级,会自动执行该脚本工具) $ cd /u01/app/oracle12/product/12.1.0/dbhome_1/rdbms/admin $ sqlplus '/as sysdba' SQL*Plus: Release 11.2.0.4.0 Production on Thu Aug 6 08:26:57 2015 Copyright (c) 1982, 2013

mysql中index与Multiple-Column Indexes区别与联系

索引对提升SELECT/UPDATE语句查询速度有着立竿见影的效果,有索引和无索引,查询速度往往差几个数量级. 本次讨论一下index(每列作为一个索引,单列索引)和Multiple-Column Indexes(多列作为一个索引,最多16列,复合索引)使用场景. 常见新建或添加索引的方式: 方式一,建表时新建 CREATE TABLE test ( id INT NOT NULL, last_name CHAR(30) NOT NULL, first_name CHAR(30) NOT NUL

11 Python Libraries You Might Not Know

11 Python Libraries You Might Not Know by Greg | January 20, 2015 There are tons of Python packages out there. So many that no one man or woman could possibly catch them all. PyPi alone has over 47,000 packages listed! Recently, with so many data sci

Ten C++11 Features Every C++ Developer Should Use

原版:http://www.codeproject.com/Articles/570638/Ten-Cplusplus-Features-Every-Cplusplus-Developer 译版:http://blogs.ejb.cc/archives/7190/top-10-new-features-you-should-know-about-c-11 This article discusses a series of features new to C++11 that all devel