oracle全文索引之同步和优化索引做了什么

一、同步索引做了什么
我们知道,在数据被修改后,不能被查询到了,直到索引被同步。那么同步索引做了那些工作呢?


suk@oracle9i> insert into t_domain values(3,'this is beijing');

已创建 1 行。

suk@oracle9i> update t_domain set doc='this is beijing' where id=3;

已更新 1 行。

suk@oracle9i> delete from t_domain where id=5;

已删除 1 行。

suk@oracle9i> commit;

提交完成。

suk@oracle9i> @begin_tracesuk@oracle9i> exec ctx_ddl.sync_index('IDX_DOMAIN');suk@oracle9i> @end_trace

摘取trace中主要的sql如下:

--发出索引同步命令
BEGIN ctx_ddl.sync_index('IDX_DOMAIN'); END;

--删除DR$WAITING中与DR$PENGING重复的信息
DELETE FROM DR$WAITING
WHERE
WTG_CID = :b1 AND WTG_PID = :b2 AND EXISTS (SELECT 1 FROM DR$PENDING
WHERE DR$PENDING.PND_CID = DR$WAITING.WTG_CID AND DR$PENDING.PND_PID =
DR$WAITING.WTG_PID AND DR$PENDING.PND_ROWID = DR$WAITING.WTG_ROWID )

这一步很重要,我们在《oracle全文索引之几个关键表》中介绍了DR$WAITING的使用原理,为了避免重复同步同一条记录的索引,提高效率,必须删除掉DR$WAITING中多余的信息。
在删除DR$WAITING的多余信息后,oracle会把DR$WAITING的记录与DR$PENGDING的记录联合,得到最终需要同步的记录的集合。
(因为这个实验中DR$WAITING表中的数据完全是DR$PENDING的子集,所以,trace没有反应合并这一步)

--通过一定的分词算法,把产生的信息插入到$I表中
insert into "SUK"."DR$IDX_DOMAIN$I"
values
(:token, :ttype, :first, :last, :count, :data)

--插入记录到$K表中
insert into "SUK"."DR$IDX_DOMAIN$K" (textkey, docid)
values
(:akeys, :adocs)

--更新$R表
select data
from
"SUK"."DR$IDX_DOMAIN$R" where row_no = :row_no for update
在trace中并没有更新$R的直接信息,但我猜测在同步索引时会更新$R表

--删除DR$PENGING的信息
delete from dr$pending
where
pnd_cid = :cid and pnd_pid = :pid and pnd_rowid = :rid

实际上,我猜测,如果删除DR$WAITING中与DR$PENGING重复的信息后,DR$WAITING还有记录的话,这一步还会删除DR$WAITIING的记录的。

--最后提交
commit


二、优化索引做了什么

优化索引可以有很多方式,不同的优化方式得到的结果会不一样,但原理应该是差不多的。我们以FULL优化为例说明。
紧接着上面的例子,我们发出命令:

suk@oracle9i> @begin_tracesuk@oracle9i> exec ctx_ddl.optimize_index('idx_domain','FULL');suk@oracle9i> @end_trace

从trace文件中摘取主要的sql:
--发出命令
BEGIN ctx_ddl.optimize_index('idx_domain','FULL'); END;

--将DR$INDEX的部分字段设置为空
UPDATE DR$INDEX SET IDX_OPT_TOKEN= NULL ,IDX_OPT_TYPE= NULL ,IDX_OPT_COUNT=
NULL
WHERE
IDX_ID = :b1

其中:
IDX_OPT_TOKEN:当次优化的起始关键字
IDX_OPT_COUNT:当次优化的doc数量

--将$N表的doc设置为需要被优化状态
update "SUK"."DR$IDX_DOMAIN$N" set nlt_mark = 'U'
where
nlt_mark != 'U'

之所以要做这一步是因为设置这些状态和删除$I表是两个事务。为了避免在更新了状态位后,没有删除$I表的相关数据的情况。

--将N$表的前16000行设置为"M"状态
update "SUK"."DR$IDX_DOMAIN$N" set nlt_mark = 'M'
where
rownum <= 16000

"M"表示正在被处理。

--更新DR$INDEX的状态
UPDATE DR$INDEX SET IDX_OPT_TOKEN=:b1,IDX_OPT_TYPE=:b2,IDX_OPT_COUNT=:b3,
IDX_DOCID_COUNT=GREATEST(IDX_DOCID_COUNT - :b3 ,0)
WHERE
IDX_ID = :b5

--提交
commit

--删除无效的docid对应的$I中数据
delete from "SUK"."DR$IDX_DOMAIN$I"
where
rowid = :rid

--删除已经优化完成的DOCID
delete from "SUK"."DR$IDX_DOMAIN$N"
where
nlt_mark = 'M'

从以上过程可以看出:oracle优化索引实际上是根据$N表记录的DOCID删除$I表对应的信息,清除$I表的垃圾数据,从而达到提供查询性能的目的。
实际上,优化索引还执行了合并token的步骤,减少索引的碎片。

在做full方式优化索引时有几下几点需要注意:
1)在9ir2以前的版本中,full方式优化索引相当于索引全部删除了重建;在9ir2后,full方式优化索引不会去重写已经被优化的记录。
2)在9ir2前,每次用full方式优化索引最多能处理16000个docid,也就是说每次优化最多能在$I表删除16000个docid对应的记录,如果无效doc很多,需要多次运行优化才能完全优化。
在9ir2及以后版本,执行一次full方式优化可以删除$I表全部的无效信息,但是,在$N表每次还是最多删除16000个docid(让人容易混淆的地方,不明白oracle为什么这样做);
如果无效doc很多,那么在执行完一次full优化后,如果不再产生新的无效doc,那么,再之后的full优化中,只是删除$N表的记录。
3)DR$INDEX中的IDX_OPT_TOKEN为空表示索引已经执行完full方式的优化。


疑问:优化时,为什么要分成两个事务?

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/231499/viewspace-63757/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/231499/viewspace-63757/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值