Oracle:带条件的全文搜索

Cli*_*ton 11 sql oracle indexing oracle-text full-text-indexing

我创建了一个Oracle Text索引,如下所示:

create index my_idx on my_table (text) indextype is ctxsys.context; 
Run Code Online (Sandbox Code Playgroud)

然后我可以做以下事情:

select * from my_table where contains(text, '%blah%') > 0;
Run Code Online (Sandbox Code Playgroud)

但是,假设我们在此表中有另一列,比如说group_id,我想要执行以下查询:

select * from my_table where contains(text, '%blah%') > 0 and group_id = 43;
Run Code Online (Sandbox Code Playgroud)

使用上面的索引,Oracle将不得不搜索包含的所有项目,'blah'然后检查它们group_id的所有内容.

理想情况下,我更喜欢只搜索项目group_id = 43,所以我想要一个像这样的索引:

create index my_idx on my_table (group_id, text) indextype is ctxsys.context; 
Run Code Online (Sandbox Code Playgroud)

有点像普通索引,因此可以为每个索引进行单独的文本搜索group_id.

有没有办法在Oracle中做这样的事情(如果这很重要,我使用的是10g)?

编辑(澄清)

考虑一个包含一百万行的表和以下两列,A以及B两个数字.假设有500个不同的值A和2000个不同的值B,每行都是唯一的.

现在我们考虑一下 select ... where A = x and B = y

索引上的索引AB单独的索引搜索B,将返回500个不同的行,然后对这些行进行连接/扫描.在任何情况下,至少需要查看500行(除了数据库是幸运的,并提前找到所需的行.

索引开启(A,B)更有效,它在一个索引搜索中找到一行.

将单独的索引group_id和我认为的文本放在一起只会给查询生成器留下两个选项.

(1)使用group_id索引,并扫描文本的所有结果行.
(2)使用文本索引,并扫描所有生成的行group_id.
(3)使用两个索引,并进行连接.

我想要的是:

(4)使用(group_id, "text")索引查找特定下的group_id文本索引,并扫描我需要的特定行/行的文本索引.不需要扫描和检查或加入,就像使用索引时一样(A,B).

Jon*_*ler 8

Oracle Text

1 - 您可以通过使用FILTER BY创建CONTEXT索引来提高性能:

create index my_idx on my_table(text) indextype is ctxsys.context filter by group_id;
Run Code Online (Sandbox Code Playgroud)

在我的测试中filter by,性能明显提高,但在group_id上使用btree索引仍然稍微快一些.

2 - CTXCAT索引使用"子索引",似乎与多列索引类似.这似乎是您正在寻找的选项(4):

begin
  ctx_ddl.create_index_set('my_table_index_set');
  ctx_ddl.add_index('my_table_index_set', 'group_id');
end;
/

create index my_idx2 on my_table(text) indextype is ctxsys.ctxcat
    parameters('index set my_table_index_set');

select * from my_table where catsearch(text, 'blah', 'group_id = 43') > 0
Run Code Online (Sandbox Code Playgroud)

这可能是最快的方法.使用上述查询对120MB的随机文本类似于您的A和B场景,只需要18个一致的获取.但在不利方面,创建CTXCAT索引需要大约11分钟,并使用1.8GB的空间.

(注意:Oracle Text似乎在这里工作正常,但我不熟悉Text,我不能保证这不是对@NullUserException等这些索引的不恰当使用.)

多列索引与索引连接

对于您在编辑中描述的情况,通常在(A,B)上使用索引和在A和B上连接单独的索引之间没有显着差异.我使用与您描述的数据类似的数据和索引构建了一些测试对于多列索引,连接仅需要7个一致性获取和2个一致性获取.

这是因为Oracle以块的形式检索数据.块通常为8K,并且索引块已经排序,因此您可以在几个块中拟合500到2000个值.如果您担心性能,通常读取和写入块的IO是唯一重要的.Oracle是否必须将几千行连接在一起是一个无关紧要的CPU时间.

但是,这不适用于Oracle Text索引.您可以使用btree索引("位图和"?)加入CONTEXT索引,但性能很差.