此查询的Postgresql索引?

此查询的Postgresql索引?,sql,postgresql,query-performance,Sql,Postgresql,Query Performance,有没有索引可以帮助进行这种查询 select p.name from person p where 'abjohncde' like '%'||p.name||'%' 使用gin和gin\u trgm\u ops的索引可用于此查询: select p.name from person p where p.name like '%john%' 但gin不适用于第一个查询。pg|u trgm适用于select*from table where field WITH'%pattern%'这样的

有没有索引可以帮助进行这种查询

select p.name 
from person p 
where 'abjohncde' like '%'||p.name||'%'
使用gin和gin\u trgm\u ops的索引可用于此查询:

select p.name from person p where p.name like '%john%'
但gin不适用于第一个查询。

pg|u trgm适用于select*from table where field WITH'%pattern%'这样的情况,但不幸的是,对于select*from table WITH'abcde'这样的表,它没有帮助,其中'abcde'字段的语义相同,但第一个字段的速度要快得多

相反,您可以尝试手动创建类似于三元索引的内容:

create or replace function my_trgm(x text)
    returns text[]
    language sql
    immutable strict
as $$
    select
        case when length(x) > 3 then
            (select array_agg(distinct lower(substr(x, i, 3))) from generate_series(1, length(x)-2) as i)
            else array[x]
        end
$$;

create or replace function public.my_trgm_1(x text)
    returns text[]
    language sql
    immutable strict
as $$
    select
        (select array_agg(distinct lower(substr(x, i, 3))) from generate_series(1, length(x)-2) as i) ||
        (select array_agg(distinct lower(substr(x, i, 2))) from generate_series(1, length(x)-1) as i) ||
        (select array_agg(distinct lower(substr(x, i, 1))) from generate_series(1, length(x)) as i)
$$;
和测试:

postgres=# create table t as select ((random()*1000)::int)::text as x from generate_series(1, 1000000);
SELECT 1000000
postgres=# create index idx_t_x on t using gin (my_trgm(x));
CREATE INDEX

postgres=# explain (analyze, verbose) select * from t where '16662' like '%'||x||'%';
                                                         QUERY PLAN                                                         
----------------------------------------------------------------------------------------------------------------------------
 Gather  (cost=1000.00..13216.67 rows=5000 width=3) (actual time=0.338..65.335 rows=8971 loops=1)
   Output: x
   Workers Planned: 2
   Workers Launched: 2
   ->  Parallel Seq Scan on public.t  (cost=0.00..11716.67 rows=2083 width=3) (actual time=0.106..59.276 rows=2990 loops=3)
         Output: x
         Filter: ('16662'::text ~~ (('%'::text || t.x) || '%'::text))
         Rows Removed by Filter: 330343
         Worker 0: actual time=0.089..57.952 rows=3126 loops=1
         Worker 1: actual time=0.124..58.830 rows=3308 loops=1
 Planning Time: 0.061 ms
 Execution Time: 65.803 ms

postgres=# explain (analyze, verbose) select * from t where my_trgm(x) <@ my_trgm_1('16662') and '16662' ~ x;
                                                       QUERY PLAN                                                       
------------------------------------------------------------------------------------------------------------------------
 Bitmap Heap Scan on public.t  (cost=184.40..6916.58 rows=43 width=3) (actual time=4.655..70.851 rows=8971 loops=1)
   Output: x
   Recheck Cond: (my_trgm(t.x) <@ '{166,666,662,16,66,62,1,6,2}'::text[])
   Filter: ('16662'::text ~ t.x)
   Heap Blocks: exact=3876
   ->  Bitmap Index Scan on idx_t_x  (cost=0.00..184.39 rows=8586 width=0) (actual time=3.534..3.534 rows=8971 loops=1)
         Index Cond: (my_trgm(t.x) <@ '{166,666,662,16,66,62,1,6,2}'::text[])
 Planning Time: 0.578 ms
 Execution Time: 71.228 ms
注意,它在一个列表上执行,因此在这个特定的测试用例中,扫描整个表可能比扫描GIN索引更有效


PS:使用一些PL语言,如plpythonu或plperl,可以更有效地插入/更新数据。

您需要一个三叉图索引,有一个现成的解决方案:和@a_horse_,据我所知,它是字段~'%'的解决方案,但不是~'%'.| | |'%'的解决方案,这太棒了,但不知何故,您的解决方案需要更长的时间,如您的示例以及我的实际用例所示。我会玩它多一点,调整一些,看看。谢谢您的想法。@user3281157如果您按原样使用我的解决方案。。。不要使用~operator-这样会花费很多~~ like的同义词,~~*是ilike的同义词;我使用~只是因为它较短: