-- Create Table with random data
create table my_table (idx number, pattern varchar2(4));
insert into my_table select level, dbms_random.string('U', 4) from dual connect by level <= 1000000;
-- Column 1 is unevenly distributed, 50% = A
update my_table set pattern= substr(pattern,1,1)||'A'||substr(pattern,3,2) where rownum <= 500000;
-- Column 2 is unevenly distributed, almost completely = B
update my_table set pattern= substr(pattern,2,1)||'B'||substr(pattern,3,2) where rownum <= 999000;
-- Build indexes
create index s1 on my_table (substr(pattern, 1, 1));
create index s2 on my_table (substr(pattern, 2, 1));
create index s3 on my_table (substr(pattern, 3, 1));
create index s4 on my_table (substr(pattern, 4, 1));
CREATE INDEX i_first3 on mytable(SUBSTR(mycolumn,1,3));
CREATE INDEX i_last3 on mytable(SUBSTR(mycolumn,-3,3));
SELECT *
FROM mytable
WHERE SUBSTR(mycolumn,1,3) = 'AAA'
AND SUBSTR(mycolumn,-3,3) = 'CCC'
CREATE INDEX i_last1 on mytable(SUBSTR(mycolumn,-1),mycolumn);
CREATE INDEX i_last2 on mytable(SUBSTR(mycolumn,-2),mycolumn);
CREATE INDEX i_last3 on mytable(SUBSTR(mycolumn,-3),mycolumn);
CREATE INDEX i_last4 on mytable(SUBSTR(mycolumn,-4),mycolumn);
CREATE INDEX i_last5 on mytable(SUBSTR(mycolumn,-5),mycolumn);
CREATE INDEX i_last6 on mytable(SUBSTR(mycolumn,-6),mycolumn);
CREATE INDEX i_last7 on mytable(SUBSTR(mycolumn,-7),mycolumn);
...etc..
SELECT *
FROM mytable
WHERE mycolumn LIKE REPLACE('AxABBBCCC','x','_')
AND SUBSTR(mycolumn,-7) = SUBSTR('AxABBBCCC',-7)
2条答案
按热度按时间3npbholx1#
正如已经写过的那样,数据的分布可能是不均匀的,这取决于数据列中的位置,并且索引访问可能根本不值得。
因此,最好将此估计留给数据库,数据库会对其进行统计。这意味着为数据列的每个位置构建索引:
根据频率,执行计划为:
jhkqcmku2#
如果通配符位于中间或末尾,并且通配符之前的前导字符匹配的记录数量相对较少,则应使用
LIKE
运算符。将“x
”替换为_
:如果你的用户不能使用
_
,并且坚持使用'x
'通配符,那么在SQL中将其替换为_
:这是我的主要答案。但是,如果你有大量以AAA开头的行,它不会很快。如果你遇到这个问题,那么根据常见的模式,有一些可能性。如果你总是看前三个字符和后三个字符,你可以将它们SUBSTR出来并索引该函数:
很明显,如果用户可以在任意位置使用通配符,而你又无法预测是哪个位置,那么这是行不通的。但是你可以做一些比较前卫的事情,比如为每个最后的字符数创建一个单独的基于函数的索引,然后根据用户提供的值,找到最后一个通配符之后的字符数,并在其上使用一个子字符串,在其余的字符上加上一个LIKE:
这将使用
i_last7
对最后7位数字进行查找(二进制搜索),然后扫描叶节点,对整个mycolumn
列(索引中的第二列)应用LIKE
运算符。它的性能比LIKE
好得多,在通配符之前只有一个字符。您还可以使用
REVERSE
和index that反转值,然后决定是否在正常值上使用LIKE
(如果通配符在值的更深处),或者在值的反转上使用LIKE
(如果通配符靠近前面)。对比
无论如何,你明白了-你的选择取决于你的查询模式和数据。希望没有任何基于函数的索引的简单
LIKE
能满足你的需求,你不需要所有这些额外的东西。你不会知道,直到你尝试它,看看它是如何执行的。最后,希望不要太频繁,您可以向表添加一个并行属性,以便如果Oracle在字符串的开头看到通配符并进行全表扫描,至少它将与直接路径读取并行读取。