我们使用 Oracle Text CTXSYS.CONTEXT 索引来索引大约 50 万行包含元信息的行。信息分布在两个表上,这些表由索引器在运行时调用的过程(功能索引)组合在一起。
当我在本地机器(简单的双核笔记本)上运行 CREATE INDEX 时,索引在大约 3 分钟内建立。在我们的数据库服务器上运行 8 核和 16G RAM 的 Solaris 上,为相同(完全相同)的数据创建索引需要大约 24 小时。
示例代码:
这是我们的两个表和 3 列的索引馈送器:
create or replace procedure docmeta_revisions_text_feeder
( p_rowid in rowid , p_clob in out nocopy clob) as v_clob CLOB begin
FOR c1 IN (select DM.DID, DM.XDESCRIB || ' ' || DM.XAUTHOR AS data
from DOCMETA DM
WHERE ROWID = p_rowid)
LOOP
v_clob := v_clob || c1.data;
FOR c2 IN (
SELECT ' ' || RV.DDOCTITLE AS data
FROM REVISIONS RV
WHERE RV.DID = c1.DID)
LOOP
v_clob := v_clob || c2.data;
END LOOP;
END LOOP;
p_clob := v_clob;
end docmeta_revisions_text_feeder
这些是偏好
BEGIN
CTX_DDL.CREATE_PREFERENCE ('concat_DM_RV_DS', 'USER_DATASTORE');
CTX_DDL.SET_ATTRIBUTE ('concat_DM_RV_DS', 'PROCEDURE',
'docmeta_revisions_text_feeder');
END;
现在我们创建索引
CREATE INDEX concat_DM_RV_idx ON DOCMETA (FULLTEXTIDX_DUMMY)
INDEXTYPE IS CTXSYS.CONTEXT
PARAMETERS ('datastore concat_DM_RV_DS
section group CTXSYS.AUTO_SECTION_GROUP
') PARALLEL 4;
数据主要由一个简单的标题或作者姓名 + 一个 <1k 文本的简短描述组成。
我尝试使用所涉及的内存设置和 PARALLEL 参数,但没有任何成功。所以我的问题来了:
最佳答案
我们终于想出了如何对索引进行拆分同步。以下是一些基本步骤,展示了我们所做的:
CREATE INDEX concat_DM_RV_idx ON DOCMETA (FULLTEXTIDX_DUMMY)
INDEXTYPE IS CTXSYS.CONTEXT
PARAMETERS ('datastore concat_DM_RV_DS section group CTXSYS.AUTO_SECTION_GROUP
NOPOPULATE
');
看到 NOPOPULATE 参数了吗?这告诉索引器它不应该开始填充/索引过程。如果您使用的是 11g,您现在手头有一个非常好的 CTX_DDL 功能,可以随意填充索引,即过程“POPULATE_PENDING”。在您的索引名称上调用它会填充 CTXSYS 表,该表包含已修改并因此不同步的行。请注意,在调用此方法后,索引器仍未启动任何操作。从 10g (?) 开始,相应的 CTX_DDL.SYNC_INDEX 过程有几个附加参数,例如“最大时间”参数。提供它,比如说,4H,你的索引器将开始同步挂起的行大约 4 小时。您按计划重复该程序并完成。
不幸的是,这在 9i 中不起作用。所以我们尝试成功地“模拟”了Oracle POPULATE_PENDING 过程。此方法的唯一限制是:您需要某种唯一的行标识符才能从表中查询相同内容的块。这是我们所做的:
1.) 使用 NOPOPULATE 创建索引(见上文)
2.) 成为 SYS/DBA/CTXSYS(是的,您可以为此调用您的管理员)。通过查询索引元表找出新创建的索引的 ID:
SELECT IDX_ID FROM CTXSYS.CTX_INDEXES WHERE IDX_NAME ='concat_DM_RV_idx';
3.) 记下在黄色纸片上产生的索引 ID,并以 CTXSYS 角色执行此插入语句,并将 <> 替换为您的索引 ID,将 <> 替换为构建索引的表的名称。唯一行标识符可以是某种文档 ID 或任何类型的可数语句,用于创建表的唯一数据块:
INSERT INTO CTXSYS.DR$PENDING (PND_CID,PND_PID,PND_ROWID,PND_TIMESTAMP)
SELECT <<your index id>>, 0, <<basetable name>>.ROWID, CURRENT_DATE
FROM gsms.DOCMETA
WHERE <<basetable unique row identifier>> < 50000;
COMMIT; -- Dont forget the COMMIT! DONT FORGET IT!!! WE MEAN IT!
“50.000”根据将作为索引器有效负载插入待处理行表中的基表的稀缺性来标记行数。根据您自己的需要进行调整。
4.) 现在我们设置好让索引器松动。
CALL CTX_DDL.SYNC_INDEX(
'CONCAT_DM_RV_IDX', -- your index name here
'100M', -- memory count
NULL, -- param for partitioned idxes
2 -- parallel count
);
将在您在步骤 3 中插入的任何行数上启动索引过程。)运行下一个块重复步骤 3。)接下来的 50.000 行左右(“其中 id 介于 50.000 和 100.000 之间”)
如果您不小心在同一组行上运行索引器,索引将强烈碎片化。清理它的唯一方法是使用 REBUILD 参数优化索引。在我们的本地机器上速度非常快,因为索引器不必运行而只需重新排列索引表的内容:
CALL CTX_DDL.OPTIMIZE_INDEX('CONCAT_DM_RV_IDX', 'REBUILD');
如果你需要一些关于索引状态和大小的元信息,你可以询问 CTX_REPORT 包:
SELECT CTX_REPORT.INDEX_SIZE('CONCAT_DM_RV_IDX') FROM DUAL;
如果您忘记了在索引时选择了哪些参数:
SELECT * FROM CTXSYS.CTX_PARAMETERS;
索引快乐!
关于oracle - 加快 Oracle Text 索引或让索引器仅在低加载时间下工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3298864/