在oracle中:我有一个表rel,其中包含这些列(object_id1,object_id2),它们关联系统中的对象对。 object_ids是varchars,前3个字符标识对象的类型。例如。用户以001开头,书籍以002开头,但还有更多类型。现在,我想通过此查询获取此表中相关的所有用户手册对:
SELECT * FROM rel WHERE rel.object_id1 LIKE '001%' AND rel.object_id2 LIKE '002%'
要做到这一点,我需要在object_id1的前三个字符和object_id2上使用b-tree索引索引。是否有可能在列的一部分上有索引,在这种情况下是前3个字符?怎么样?
答案 0 :(得分:5)
您可以创建基于函数的索引
CREATE INDEX idx_rel_obj_id
ON( substr( object_id1, 1, 3 ),
substr( object_id2, 1, 3 ) );
但是你的查询需要使用相同的函数调用
SELECT *
FROM rel
WHERE substr( rel.object_id1, 1, 3 ) = '001'
AND substr( rel.object_id2, 1, 3 ) = '002'
通常,您将创建标记为确定性的用户定义函数(即get_object_type),并在索引定义和查询中使用这些用户定义的函数,以确保某人不会无意中使用不同的函数构造以获取字段的前三个字符,这将阻止使用基于函数的索引。
所有这一切,在表中有一列,其中前三个字符代表一些其他数据元素违反了基本规范化。将前三个字符存储在单独的列中而不是尝试在运行时解析复合列几乎总是更好。
答案 1 :(得分:2)
您可以使用基于函数的索引来执行此操作。
假设:
SQL> create table t (a varchar(10));
Table created.
然后,您可以在该列的前三个字符上创建索引:
SQL> create index t_s on t(substr(a,0,3));
Index created.
如果在查询中使用完全相同的函数,将使用它:
SQL> set autotrace traceonly;
SQL> select * from t where SUBSTR(a,0,3) = '001' ;
no rows selected
Execution Plan
----------------------------------------------------------
Plan hash value: 2699450933
------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 7 | 1 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| T | 1 | 7 | 1 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | T_S | 1 | | 1 (0)| 00:00:01 |
------------------------------------------------------------------------------------
...
答案 2 :(得分:0)
如果您无法更改物理模式以将对象类型值放在单独的列中(最常用的方法),则可以使用SUBSTR函数在子字符串上创建基于函数的索引,如:
CREATE INDEX rel_idx_f01 ON rel (SUBSTR(object_id1, 1, 3));
显然,每个object_id1和object_id2列都需要一个索引。