背景

在现实生活中,很多地方会用到相似搜索,例如

1、打车,要去某个地方,我们输入的目的地可能和数据库里面存的并不完全一致。所以只能通过相似搜索来实现。

2、搜索问题,同样的道理,我们搜的问题可能和存的问题不完全一致。只能通过相似搜索来匹配。

3、搜索兴趣点,等。

实际上PostgreSQL就可以支持相似搜索,包括图片、数组、文本等相似搜索。对于文本,可以使用pg_trgm插件来实现相似搜索。

这是纯英文字符串的测试,100亿量级(每行32个随机英文字母+数组的组合),模糊查询毫秒级别。

《PostgreSQL 百亿数据 秒级响应 正则及模糊查询》

相似查询使用同样的插件和索引。本文针对随机中文,相似搜索进行测试,看看PostgreSQL 单机性能如何?

构建测试样本数据

1、生成随机中文的函数


1. -- 生成随机汉字符串
2. create or replace function gen_hanzi(int) returns text as $$
3. declare
4. res text;
5. begin
6. if $1 >=1 then
7. select string_agg(chr(19968+(random()*20901)::int), '') into res from generate_series(1,$1);
8. return res;
9. end if;
10. return null;
11. end;
12. $$ language plpgsql strict;

2、使用分区表来提高写入、查询性能

如何建分区表,请参考:

《PostgreSQL 查询涉及分区表过多导致的性能问题 - 性能诊断与优化(大量BIND, spin lock, SLEEP进程)》

《PostgreSQL 商用版本EPAS(阿里云ppas) - 分区表性能优化 (堪比pg_pathman)》

《PostgreSQL 传统 hash 分区方法和性能》

《PostgreSQL 10 内置分区 vs pg_pathman perf profiling》

《PostgreSQL 10.0 preview 功能增强 - 内置分区表》

本文为了测试方便,未使用以上分区方法,请注意。

3、建父表(为了加速导入,使用了unlogged table,生成请勿使用)


1. create unlogged table tbl(id int primary key, info text);

3. alter table tbl set (parallel_workers =64);

5. create extension pg_trgm;

4、建64个子表


1. do language plpgsql $$
2. declare
3. begin
4. for i in 0..63
5. loop
6. execute format('drop table if exists tbl%s ', i);
7. execute format('create unlogged table tbl%s (like tbl including all) inherits(tbl)', i);
8. -- 提前设置好表级并行度,方便后面做并行测试
9. execute format('alter table tbl%s set (parallel_workers =64)', i);
10. end loop;
11. end;
12. $$;

5、往分区中写入10亿条测试数据

快速写入方法如下,使用dblink异步调用并行加载。


1. create or replace function conn(
2. name,   -- dblink名字
3. text    -- 连接串,URL
4. ) returns void as $$
5. declare
6. begin
7. perform dblink_connect($1, $2);
8. return;
9. exception when others then
10. return;
11. end;
12. $$ language plpgsql strict;

64个分区,每行64个随机汉字,每个分区写入15625000行,总共插入10亿行。


1. create extension dblink;

3. do language plpgsql $$
4. declare
5. begin
6. for i in 0..63
7. loop
8. perform conn('link'||i,  'hostaddr=127.0.0.1 user=postgres dbname=postgres');
9. perform dblink_send_query('link'||i, format('insert into tbl%s select generate_series(1, 15625000), gen_hanzi(64)', i));
10. end loop;
11. end;
12. $$;

这种并行写入方法,把CPU用了个精光,马力全开,高速写入10亿条随机文本。


1. top - 14:49:48 up 217 days,  4:29,  3 users,  load average: 64.33, 63.08, 46.16
2. Tasks: 756 total,  65 running, 691 sleeping,   0 stopped,   0 zombie
3. %Cpu(s): 96.5 us,  3.5 sy,  0.0 ni,  0.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
4. KiB Mem : 52807456+total,  7624988 free, 19696912 used, 50075267+buff/cache
5. KiB Swap:        0 total,        0 free,        0 used. 37125398+avail Mem

写入完毕:

10亿记录,表占用空间223GB,写入记录耗时18分钟。

样本如下:


1. postgres=# select * from tbl limit 10;
2. id |                                                               info
3. ----+----------------------------------------------------------------------------------------------------------------------------------
4. 1 | 懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁内橰畁蜫征瘭缆竟
5. 2 | 荓嚅鑀鑬抾诐裹坲雚囻卥饸數拰絔刦霨礸诿廓琫颧仯瞱捲瘰弶瓴鹝逼倭舌飂陭盒寚芘怦敍种椡檱玠肙羡兎蒿眤粆焙蟸儌樛裦窽美影诳哜帪粊圊鈵疧
6. 3 | 齷楣莁艪箉髎岒險旚舲瞞靻薀岹滺扡習坍敮鯭鈳鈫篖刀繹芲截孞讼咺茅讎瀝曡湓鶦戊糥钫秤彲沤熻雲筝銵妮宊鰂焜埒躐採薨銐鐚梶唕俓响寏蓘鉛緬
7. 4 | 鶹愈篭怞迭烲调侺辖帘颬歎儨劵磘鼪痐芪踖譱梮脁翦荣蠖膹訰闥曬糦琬攀迮偳真耷獦捼臱捗玕竷肥皽羬姘癃嗗躂撴鍉垊鞵玊賮耦喞睹癦溊咺鲒薋隨
8. 5 | 鼅崄眹狆犁妅蠝頖虼椝漮暄瓴靰湛揑屿懿浛咏螈媤蚴輦萝嵵帋諗婢閖臙姂勵奮纈睶擳最濧鵯舜鄕摎坫裠蒩洽靟颧貘鷮肋餼蓽瀌綴鑳耗棦估瘈鲿嫲竾
9. 6 | 嚈譺勏浺勔璶歅蛰春膒遜你暖巳颿徙鲋霈鈣阣籡把琲焮钢輗牞欅谱罐頃钹欤鳑抏濸燢翓坄訇懁馠譧穗埮蒂诰哔篥繮鳷墡鋸熃篏蟵惶予单鼧翘鵗鐻鳼
10. 7 | 骄圥浏況裸皓圣鲹炎钊睫穼祧掶腐喧鐤红恈蝷傀踗濇捶躟甜拸滒狎垎氩涭悳譸豭鮬执閐飀蓴詵炆忋搷蘼錛毞窻爘縦抌璘沙葓訍宓姊鼅籥纘囯骎鹄榢
11. 8 | 虢謌斩髈胷廄耘毇腊釣臾柡蕙丷钛埋繝垃繣鳶跖棋壤馟栬蝉碒焚舲眱貽棯抙勀搒閐掄阪憲雎表閯弊減闦吀矦璞嶃嚤燯鵘煯糓靓讛摷灀崐颩饱鯍懳層
12. 9 | 仨砆剏摬溋昁宕坍尋沟睨剌犟侩磫舢塎鳚翕箽稈瞂枲避駂盃覄鎎狪鵷偍珒痘咜訾陣沝韔下窨擎睳绵襭礜堺毩荪啰鶾徂腸疛礴牒澹偒就探甼娃旯鬎臛
13. 10 | 沌薧碙謩緖碤昬钣偱霠繫箎侶鱔归圦驭烔誝灣鰈嵋鈜鹚歼嘘珰睿済潙妵貓啛葎砗蔱嵍遂稰徾螾壶赌襴喥麞銙偭濍綒狐氰賜敇櫤墳浟郕舲赧悉跧穕柤
14. (10 rows)

6、创建索引(实际生产中,索引可以先建好,这里主要是为了加速生成速度)


1. do language plpgsql $$
2. declare
3. begin
4. create index idx_tbl_info on tbl using gin(info gin_trgm_ops);

6. for i in 0..63
7. loop
8. perform conn('link'||i,  'hostaddr=127.0.0.1 user=postgres dbname=postgres');
9. perform dblink_send_query('link'||i, format('create index idx_tbl%s_info on tbl%s using gin(info gin_trgm_ops);', i, i));
10. end loop;
11. end;
12. $$;

10亿记录,GIN倒排索引占用空间332GB,创建索引耗时接近180分钟。

索引创建速度解释:

由于这个CASE写入的字符串是几万个汉字里面的完全随机的汉字,所以GIN倒排索引的TOKEN特别多。这个CASE比正常生产数据的索引要大很大,正常索引不会这么大,正常创建速度也会比这个快。但是创建GIN索引的速度相比BTREE确实是要慢很多的(结构所致)。如果是BTREE索引,应该会在5分钟内创建完成。

相似查询SQL用法

1、查看当前相似度阈值


1. select show_limit();
2. show_limit
3. ------------
4. 0.3
5. (1 row)

2、设置当前会话相似度阈值,其他设置详见末尾部分


1. select set_limit(0.9);

3、相似搜索的响应速度与用户设置的相似度有关,用户设置的相似度匹配到的值越多,速度越慢。匹配到的值越少(即精度越高),响应速度越快。


1. -- 响应速度更慢
2. postgres=# select set_limit(0.1);
3. set_limit
4. -----------
5. 0.1
6. (1 row)

8. -- 响应速度更快
9. postgres=# select set_limit(0.9);
10. set_limit
11. -----------
12. 0.9
13. (1 row)

4、根据输入文本,查询与之相似的文本,并按相似排序输出。


1. select similarity(info, '输入搜索词') as sml, -- 计算输入词与存储字符串的相似度
2. * from tbl
3. where info % '输入搜索词'    -- 相似度超过阈值
4. order by sml desc            -- 按相似度排序(倒排,越相似的排在越前面)
5. limit 10;

SQL耗时:71毫秒


1. postgres=# select set_limit(0.7);
2. set_limit
3. -----------
4. 0.7
5. (1 row)

7. select similarity(info, '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁') as sml, -- 计算输入词与存储字符串的相似度
8. * from tbl
9. where info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'    -- 相似度超过阈值
10. order by sml desc            -- 按相似度排序(倒排,越相似的排在越前面)
11. limit 10;

13. sml  | id |                                                               info
14. ------+----+----------------------------------------------------------------------------------------------------------------------------------
15. 0.75 |  1 | 懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁内橰畁蜫征瘭缆竟
16. (1 row)

18. Time: 71.627 ms

5、SQL执行计划如下,使用到了索引扫描,所以非常快。


1. explain select similarity(info, '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁') as sml, -- 计算输入词与存储字符串的相似度
2. * from tbl
3. where info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'    -- 相似度超过阈值
4. order by sml desc            -- 按相似度排序(倒排,越相似的排在越前面)
5. limit 10;

9. QUERY PLAN
10. ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
11. Limit  (cost=1025136.11..1025137.35 rows=10 width=204)
12. ->  Gather Merge  (cost=1025136.11..1148791.31 rows=999944 width=204)
13. Workers Planned: 8
14. ->  Sort  (cost=1024135.97..1024448.45 rows=124993 width=204)
15. Sort Key: (similarity(tbl2.info, '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)) DESC
16. ->  Result  (cost=554.09..1021434.91 rows=124993 width=204)
17. ->  Parallel Append  (cost=554.09..1019872.50 rows=124993 width=200)
18. ->  Parallel Bitmap Heap Scan on tbl2  (cost=554.09..15935.51 rows=1953 width=200)
19. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
20. ->  Bitmap Index Scan on idx_tbl2_info  (cost=0.00..550.19 rows=15625 width=0)
21. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
22. ->  Parallel Bitmap Heap Scan on tbl3  (cost=554.09..15935.51 rows=1953 width=200)
23. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
24. ->  Bitmap Index Scan on idx_tbl3_info  (cost=0.00..550.19 rows=15625 width=0)
25. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
26. ->  Parallel Bitmap Heap Scan on tbl4  (cost=554.09..15935.51 rows=1953 width=200)
27. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
28. ->  Bitmap Index Scan on idx_tbl4_info  (cost=0.00..550.19 rows=15625 width=0)
29. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
30. ->  Parallel Bitmap Heap Scan on tbl5  (cost=554.09..15935.51 rows=1953 width=200)
31. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
32. ->  Bitmap Index Scan on idx_tbl5_info  (cost=0.00..550.19 rows=15625 width=0)
33. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
34. ->  Parallel Bitmap Heap Scan on tbl7  (cost=554.09..15935.51 rows=1953 width=200)
35. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
36. ->  Bitmap Index Scan on idx_tbl7_info  (cost=0.00..550.19 rows=15625 width=0)
37. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
38. ->  Parallel Bitmap Heap Scan on tbl8  (cost=554.09..15935.51 rows=1953 width=200)
39. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
40. ->  Bitmap Index Scan on idx_tbl8_info  (cost=0.00..550.19 rows=15625 width=0)
41. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
42. ->  Parallel Bitmap Heap Scan on tbl9  (cost=554.09..15935.51 rows=1953 width=200)
43. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
44. ->  Bitmap Index Scan on idx_tbl9_info  (cost=0.00..550.19 rows=15625 width=0)
45. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
46. ->  Parallel Bitmap Heap Scan on tbl10  (cost=554.09..15935.51 rows=1953 width=200)
47. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
48. ->  Bitmap Index Scan on idx_tbl10_info  (cost=0.00..550.19 rows=15625 width=0)
49. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
50. ->  Parallel Bitmap Heap Scan on tbl11  (cost=554.09..15935.51 rows=1953 width=200)
51. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
52. ->  Bitmap Index Scan on idx_tbl11_info  (cost=0.00..550.19 rows=15625 width=0)
53. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
54. ->  Parallel Bitmap Heap Scan on tbl12  (cost=554.09..15935.51 rows=1953 width=200)
55. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
56. ->  Bitmap Index Scan on idx_tbl12_info  (cost=0.00..550.19 rows=15625 width=0)
57. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
58. ->  Parallel Bitmap Heap Scan on tbl13  (cost=554.09..15935.51 rows=1953 width=200)
59. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
60. ->  Bitmap Index Scan on idx_tbl13_info  (cost=0.00..550.19 rows=15625 width=0)
61. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
62. ->  Parallel Bitmap Heap Scan on tbl14  (cost=554.09..15935.51 rows=1953 width=200)
63. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
64. ->  Bitmap Index Scan on idx_tbl14_info  (cost=0.00..550.19 rows=15625 width=0)
65. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
66. ->  Parallel Bitmap Heap Scan on tbl16  (cost=554.09..15935.51 rows=1953 width=200)
67. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
68. ->  Bitmap Index Scan on idx_tbl16_info  (cost=0.00..550.19 rows=15625 width=0)
69. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
70. ->  Parallel Bitmap Heap Scan on tbl17  (cost=554.09..15935.51 rows=1953 width=200)
71. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
72. ->  Bitmap Index Scan on idx_tbl17_info  (cost=0.00..550.19 rows=15625 width=0)
73. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
74. ->  Parallel Bitmap Heap Scan on tbl18  (cost=554.09..15935.51 rows=1953 width=200)
75. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
76. ->  Bitmap Index Scan on idx_tbl18_info  (cost=0.00..550.19 rows=15625 width=0)
77. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
78. ->  Parallel Bitmap Heap Scan on tbl19  (cost=554.09..15935.51 rows=1953 width=200)
79. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
80. ->  Bitmap Index Scan on idx_tbl19_info  (cost=0.00..550.19 rows=15625 width=0)
81. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
82. ->  Parallel Bitmap Heap Scan on tbl20  (cost=554.09..15935.51 rows=1953 width=200)
83. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
84. ->  Bitmap Index Scan on idx_tbl20_info  (cost=0.00..550.19 rows=15625 width=0)
85. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
86. ->  Parallel Bitmap Heap Scan on tbl21  (cost=554.09..15935.51 rows=1953 width=200)
87. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
88. ->  Bitmap Index Scan on idx_tbl21_info  (cost=0.00..550.19 rows=15625 width=0)
89. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
90. ->  Parallel Bitmap Heap Scan on tbl22  (cost=554.09..15935.51 rows=1953 width=200)
91. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
92. ->  Bitmap Index Scan on idx_tbl22_info  (cost=0.00..550.19 rows=15625 width=0)
93. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
94. ->  Parallel Bitmap Heap Scan on tbl23  (cost=554.09..15935.51 rows=1953 width=200)
95. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
96. ->  Bitmap Index Scan on idx_tbl23_info  (cost=0.00..550.19 rows=15625 width=0)
97. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
98. ->  Parallel Bitmap Heap Scan on tbl24  (cost=554.09..15935.51 rows=1953 width=200)
99. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
100. ->  Bitmap Index Scan on idx_tbl24_info  (cost=0.00..550.19 rows=15625 width=0)
101. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
102. ->  Parallel Bitmap Heap Scan on tbl25  (cost=554.09..15935.51 rows=1953 width=200)
103. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
104. ->  Bitmap Index Scan on idx_tbl25_info  (cost=0.00..550.19 rows=15625 width=0)
105. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
106. ->  Parallel Bitmap Heap Scan on tbl26  (cost=554.09..15935.51 rows=1953 width=200)
107. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
108. ->  Bitmap Index Scan on idx_tbl26_info  (cost=0.00..550.19 rows=15625 width=0)
109. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
110. ->  Parallel Bitmap Heap Scan on tbl28  (cost=554.09..15935.51 rows=1953 width=200)
111. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
112. ->  Bitmap Index Scan on idx_tbl28_info  (cost=0.00..550.19 rows=15625 width=0)
113. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
114. ->  Parallel Bitmap Heap Scan on tbl29  (cost=554.09..15935.51 rows=1953 width=200)
115. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
116. ->  Bitmap Index Scan on idx_tbl29_info  (cost=0.00..550.19 rows=15625 width=0)
117. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
118. ->  Parallel Bitmap Heap Scan on tbl30  (cost=554.09..15935.51 rows=1953 width=200)
119. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
120. ->  Bitmap Index Scan on idx_tbl30_info  (cost=0.00..550.19 rows=15625 width=0)
121. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
122. ->  Parallel Bitmap Heap Scan on tbl31  (cost=554.09..15935.51 rows=1953 width=200)
123. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
124. ->  Bitmap Index Scan on idx_tbl31_info  (cost=0.00..550.19 rows=15625 width=0)
125. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
126. ->  Parallel Bitmap Heap Scan on tbl33  (cost=554.09..15935.51 rows=1953 width=200)
127. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
128. ->  Bitmap Index Scan on idx_tbl33_info  (cost=0.00..550.19 rows=15625 width=0)
129. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
130. ->  Parallel Bitmap Heap Scan on tbl34  (cost=554.09..15935.51 rows=1953 width=200)
131. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
132. ->  Bitmap Index Scan on idx_tbl34_info  (cost=0.00..550.19 rows=15625 width=0)
133. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
134. ->  Parallel Bitmap Heap Scan on tbl35  (cost=554.09..15935.51 rows=1953 width=200)
135. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
136. ->  Bitmap Index Scan on idx_tbl35_info  (cost=0.00..550.19 rows=15625 width=0)
137. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
138. ->  Parallel Bitmap Heap Scan on tbl36  (cost=554.09..15935.51 rows=1953 width=200)
139. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
140. ->  Bitmap Index Scan on idx_tbl36_info  (cost=0.00..550.19 rows=15625 width=0)
141. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
142. ->  Parallel Bitmap Heap Scan on tbl37  (cost=554.09..15935.51 rows=1953 width=200)
143. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
144. ->  Bitmap Index Scan on idx_tbl37_info  (cost=0.00..550.19 rows=15625 width=0)
145. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
146. ->  Parallel Bitmap Heap Scan on tbl38  (cost=554.09..15935.51 rows=1953 width=200)
147. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
148. ->  Bitmap Index Scan on idx_tbl38_info  (cost=0.00..550.19 rows=15625 width=0)
149. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
150. ->  Parallel Bitmap Heap Scan on tbl39  (cost=554.09..15935.51 rows=1953 width=200)
151. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
152. ->  Bitmap Index Scan on idx_tbl39_info  (cost=0.00..550.19 rows=15625 width=0)
153. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
154. ->  Parallel Bitmap Heap Scan on tbl41  (cost=554.09..15935.51 rows=1953 width=200)
155. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
156. ->  Bitmap Index Scan on idx_tbl41_info  (cost=0.00..550.19 rows=15625 width=0)
157. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
158. ->  Parallel Bitmap Heap Scan on tbl42  (cost=554.09..15935.51 rows=1953 width=200)
159. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
160. ->  Bitmap Index Scan on idx_tbl42_info  (cost=0.00..550.19 rows=15625 width=0)
161. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
162. ->  Parallel Bitmap Heap Scan on tbl44  (cost=554.09..15935.51 rows=1953 width=200)
163. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
164. ->  Bitmap Index Scan on idx_tbl44_info  (cost=0.00..550.19 rows=15625 width=0)
165. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
166. ->  Parallel Bitmap Heap Scan on tbl45  (cost=554.09..15935.51 rows=1953 width=200)
167. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
168. ->  Bitmap Index Scan on idx_tbl45_info  (cost=0.00..550.19 rows=15625 width=0)
169. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
170. ->  Parallel Bitmap Heap Scan on tbl46  (cost=554.09..15935.51 rows=1953 width=200)
171. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
172. ->  Bitmap Index Scan on idx_tbl46_info  (cost=0.00..550.19 rows=15625 width=0)
173. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
174. ->  Parallel Bitmap Heap Scan on tbl47  (cost=554.09..15935.51 rows=1953 width=200)
175. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
176. ->  Bitmap Index Scan on idx_tbl47_info  (cost=0.00..550.19 rows=15625 width=0)
177. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
178. ->  Parallel Bitmap Heap Scan on tbl48  (cost=554.09..15935.51 rows=1953 width=200)
179. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
180. ->  Bitmap Index Scan on idx_tbl48_info  (cost=0.00..550.19 rows=15625 width=0)
181. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
182. ->  Parallel Bitmap Heap Scan on tbl49  (cost=554.09..15935.51 rows=1953 width=200)
183. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
184. ->  Bitmap Index Scan on idx_tbl49_info  (cost=0.00..550.19 rows=15625 width=0)
185. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
186. ->  Parallel Bitmap Heap Scan on tbl50  (cost=554.09..15935.51 rows=1953 width=200)
187. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
188. ->  Bitmap Index Scan on idx_tbl50_info  (cost=0.00..550.19 rows=15625 width=0)
189. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
190. ->  Parallel Bitmap Heap Scan on tbl51  (cost=554.09..15935.51 rows=1953 width=200)
191. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
192. ->  Bitmap Index Scan on idx_tbl51_info  (cost=0.00..550.19 rows=15625 width=0)
193. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
194. ->  Parallel Bitmap Heap Scan on tbl52  (cost=554.09..15935.51 rows=1953 width=200)
195. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
196. ->  Bitmap Index Scan on idx_tbl52_info  (cost=0.00..550.19 rows=15625 width=0)
197. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
198. ->  Parallel Bitmap Heap Scan on tbl53  (cost=554.09..15935.51 rows=1953 width=200)
199. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
200. ->  Bitmap Index Scan on idx_tbl53_info  (cost=0.00..550.19 rows=15625 width=0)
201. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
202. ->  Parallel Bitmap Heap Scan on tbl55  (cost=554.09..15935.51 rows=1953 width=200)
203. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
204. ->  Bitmap Index Scan on idx_tbl55_info  (cost=0.00..550.19 rows=15625 width=0)
205. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
206. ->  Parallel Bitmap Heap Scan on tbl56  (cost=554.09..15935.51 rows=1953 width=200)
207. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
208. ->  Bitmap Index Scan on idx_tbl56_info  (cost=0.00..550.19 rows=15625 width=0)
209. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
210. ->  Parallel Bitmap Heap Scan on tbl57  (cost=554.09..15935.51 rows=1953 width=200)
211. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
212. ->  Bitmap Index Scan on idx_tbl57_info  (cost=0.00..550.19 rows=15625 width=0)
213. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
214. ->  Parallel Bitmap Heap Scan on tbl58  (cost=554.09..15935.51 rows=1953 width=200)
215. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
216. ->  Bitmap Index Scan on idx_tbl58_info  (cost=0.00..550.19 rows=15625 width=0)
217. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
218. ->  Parallel Bitmap Heap Scan on tbl59  (cost=554.09..15935.51 rows=1953 width=200)
219. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
220. ->  Bitmap Index Scan on idx_tbl59_info  (cost=0.00..550.19 rows=15625 width=0)
221. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
222. ->  Parallel Bitmap Heap Scan on tbl61  (cost=554.09..15935.51 rows=1953 width=200)
223. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
224. ->  Bitmap Index Scan on idx_tbl61_info  (cost=0.00..550.19 rows=15625 width=0)
225. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
226. ->  Parallel Bitmap Heap Scan on tbl62  (cost=554.09..15935.51 rows=1953 width=200)
227. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
228. ->  Bitmap Index Scan on idx_tbl62_info  (cost=0.00..550.19 rows=15625 width=0)
229. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
230. ->  Parallel Bitmap Heap Scan on tbl63  (cost=554.09..15935.51 rows=1953 width=200)
231. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
232. ->  Bitmap Index Scan on idx_tbl63_info  (cost=0.00..550.19 rows=15625 width=0)
233. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
234. ->  Parallel Bitmap Heap Scan on tbl0  (cost=554.09..15935.51 rows=1953 width=200)
235. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
236. ->  Bitmap Index Scan on idx_tbl0_info  (cost=0.00..550.19 rows=15625 width=0)
237. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
238. ->  Parallel Bitmap Heap Scan on tbl1  (cost=554.09..15935.51 rows=1953 width=200)
239. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
240. ->  Bitmap Index Scan on idx_tbl1_info  (cost=0.00..550.19 rows=15625 width=0)
241. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
242. ->  Parallel Bitmap Heap Scan on tbl6  (cost=554.09..15935.51 rows=1953 width=200)
243. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
244. ->  Bitmap Index Scan on idx_tbl6_info  (cost=0.00..550.19 rows=15625 width=0)
245. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
246. ->  Parallel Bitmap Heap Scan on tbl15  (cost=554.09..15935.51 rows=1953 width=200)
247. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
248. ->  Bitmap Index Scan on idx_tbl15_info  (cost=0.00..550.19 rows=15625 width=0)
249. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
250. ->  Parallel Bitmap Heap Scan on tbl27  (cost=554.09..15935.51 rows=1953 width=200)
251. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
252. ->  Bitmap Index Scan on idx_tbl27_info  (cost=0.00..550.19 rows=15625 width=0)
253. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
254. ->  Parallel Bitmap Heap Scan on tbl32  (cost=554.09..15935.51 rows=1953 width=200)
255. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
256. ->  Bitmap Index Scan on idx_tbl32_info  (cost=0.00..550.19 rows=15625 width=0)
257. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
258. ->  Parallel Bitmap Heap Scan on tbl40  (cost=554.09..15935.51 rows=1953 width=200)
259. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
260. ->  Bitmap Index Scan on idx_tbl40_info  (cost=0.00..550.19 rows=15625 width=0)
261. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
262. ->  Parallel Bitmap Heap Scan on tbl43  (cost=554.09..15935.51 rows=1953 width=200)
263. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
264. ->  Bitmap Index Scan on idx_tbl43_info  (cost=0.00..550.19 rows=15625 width=0)
265. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
266. ->  Parallel Bitmap Heap Scan on tbl54  (cost=554.09..15935.51 rows=1953 width=200)
267. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
268. ->  Bitmap Index Scan on idx_tbl54_info  (cost=0.00..550.19 rows=15625 width=0)
269. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
270. ->  Parallel Bitmap Heap Scan on tbl60  (cost=554.09..15935.51 rows=1953 width=200)
271. Recheck Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
272. ->  Bitmap Index Scan on idx_tbl60_info  (cost=0.00..550.19 rows=15625 width=0)
273. Index Cond: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
274. ->  Parallel Seq Scan on tbl  (cost=0.00..0.00 rows=1 width=36)
275. Filter: (info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'::text)
276. (265 rows)

6、强制使用并行,PostgreSQL 11支持多个分区并行执行,速度将更快。


1. set enable_parallel_append =on;
2. set max_parallel_workers_per_gather =16;
3. set parallel_setup_cost =0;
4. set parallel_tuple_cost =0;
5. set min_parallel_table_scan_size =0;
6. set min_parallel_index_scan_size =0;
7. set enable_parallel_append =on;


1. postgres=# select set_limit(0.7);
2. set_limit
3. -----------
4. 0.7
5. (1 row)

7. explain select similarity(info, '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁') as sml, -- 计算输入词与存储字符串的相似度
8. * from tbl
9. where info % '懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁'    -- 相似度超过阈值
10. order by sml desc            -- 按相似度排序(倒排,越相似的排在越前面)
11. limit 10;

加了并行后,SQL耗时:40毫秒(因为本来就已经很快了,所以加并行度性能几乎没有提高,当计算量很大时,性能会提升明显)


1. sml  | id |                                                               info
2. ------+----+----------------------------------------------------------------------------------------------------------------------------------
3. 0.75 |  1 | 懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁内橰畁蜫征瘭缆竟
4. (1 row)

6. Time: 40.298 ms

相似查询性能压测

1、构建压测函数,从现有记录中,使用主键随机提取一条字符串(并加工处理,生成一个新的具有一定相似度的字符串)。

使用 substring(info,1,28)||gen_hanzi(4)||substring(info,29,28) 将得到相似度为0.75的一个新字符串。


1. 从第1位开始,取28位,然后插入4个随机中文,再从29位开始取28位。这个字符串作为相似查询的输入。相似度为0.75。

3. postgres=# select substring(info,1,28)||gen_hanzi(4)||substring(info,29,28) newval, info, similarity(substring(info,1,28)||gen_hanzi(4)||substring(info,29,28) , info) from tbl limit 10;
4. -[ RECORD 1 ]--------------------------------------------------------------------------------------------------------------------------------
5. newval     | 懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦焳邹祧鵅莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁
6. info       | 懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁内橰畁蜫征瘭缆竟
7. similarity | 0.75
8. -[ RECORD 2 ]--------------------------------------------------------------------------------------------------------------------------------
9. newval     | 荓嚅鑀鑬抾诐裹坲雚囻卥饸數拰絔刦霨礸诿廓琫颧仯瞱捲瘰弶瓴叠濷賨櫕鹝逼倭舌飂陭盒寚芘怦敍种椡檱玠肙羡兎蒿眤粆焙蟸儌樛裦窽美
10. info       | 荓嚅鑀鑬抾诐裹坲雚囻卥饸數拰絔刦霨礸诿廓琫颧仯瞱捲瘰弶瓴鹝逼倭舌飂陭盒寚芘怦敍种椡檱玠肙羡兎蒿眤粆焙蟸儌樛裦窽美影诳哜帪粊圊鈵疧
11. similarity | 0.75
12. -[ RECORD 3 ]--------------------------------------------------------------------------------------------------------------------------------
13. newval     | 齷楣莁艪箉髎岒險旚舲瞞靻薀岹滺扡習坍敮鯭鈳鈫篖刀繹芲截孞熒镻缮蜝讼咺茅讎瀝曡湓鶦戊糥钫秤彲沤熻雲筝銵妮宊鰂焜埒躐採薨銐鐚
14. info       | 齷楣莁艪箉髎岒險旚舲瞞靻薀岹滺扡習坍敮鯭鈳鈫篖刀繹芲截孞讼咺茅讎瀝曡湓鶦戊糥钫秤彲沤熻雲筝銵妮宊鰂焜埒躐採薨銐鐚梶唕俓响寏蓘鉛緬
15. similarity | 0.75

压测函数如下


1. -- 使用随机字符串进行相似搜索(用于压测)
2. create or replace function get_tbl(int) returns setof record as
3. $$
4. declare
5. str text;
6. begin
7. perform set_limit(0.7);

9. -- 从第1位开始,取28位,然后插入4个随机中文,再从29位开始取28位。这个字符串作为相似查询的输入。相似度为0.75。
10. select substring(info,1,28)||gen_hanzi(4)||substring(info,29,28) into str from tbl where id=$1 limit 1;

12. return query execute format($_$select similarity(info, %L) as sml,   -- 计算输入词与存储字符串的相似度
13. * from tbl
14. where info %% %L             -- 相似度超过阈值
15. order by sml desc            -- 按相似度排序(倒排,越相似的排在越前面)
16. limit 10$_$,  str, str);
17. end;
18. $$ language plpgsql strict;

查询测试


1. postgres=# select * from get_tbl(1) as t(sml float4, id int, info text);
2. sml  | id |                                                               info
3. ------+----+----------------------------------------------------------------------------------------------------------------------------------
4. 0.75 |  1 | 懛瑌娺罊鶩凳芹緔茙蠡慺礛唾霹蹺憙胣緗犭昉鬪蒽麴牵癰嚒巈蔦莥钶们鞀楝嬦眥条弘娸霵鐲鑚夊涨鮗傞屽嶋莁豓舸鮉蟙材骘媨迁内橰畁蜫征瘭缆竟
5. (1 row)

7. Time: 92.229 ms

压测脚本


1. vi test.sql
2. \set id random(1,15625000)
3. select * from get_tbl(1) as t(sml float4, id int, info text);

压测


1. -- 并行度调低
2. alter role postgres set max_parallel_workers_per_gather =2;

4. pgbench -M prepared -n -r -P 1 -f ./test.sql -c 32 -j 32 -T 120

6. transaction type: ./test.sql
7. scaling factor: 1
8. query mode: prepared
9. number of clients: 64
10. number of threads: 64
11. duration: 120 s
12. number of transactions actually processed: 51503
13. latency average = 149.175 ms
14. latency stddev = 20.054 ms
15. tps = 428.589421 (including connections establishing)
16. tps = 428.699150 (excluding connections establishing)
17. statement latencies in milliseconds:
18. 0.003  \set id random(1,15625000)
19. 149.311  select * from get_tbl(1) as t(sml float4, id int, info text);

性能瓶颈分析:

1、CPU跑满,IO也蛮高


1. top - 19:32:05 up 217 days,  9:11,  3 users,  load average: 38.04, 21.38, 11.92
2. Tasks: 768 total,  57 running, 710 sleeping,   0 stopped,   1 zombie
3. %Cpu(s): 82.0 us, 12.8 sy,  0.0 ni,  4.1 id,  1.1 wa,  0.0 hi,  0.0 si,  0.0 st
4. KiB Mem : 52807456+total, 11373780 free, 14563392 used, 50213737+buff/cache
5. KiB Swap:        0 total,        0 free,        0 used. 35995504+avail Mem

CPU耗费主要是bitmapscan, cpu进行tuple recheck造成。

IO耗费,主要是数据+索引已经接近600GB,超过了内存大小,涉及到大量的IO访问。

小结

数据构造性能指标:

10亿文本数据写入耗时: 18分钟。

GIN索引生成耗时: 180分钟。

空间占用:

10亿文本: 223 GB

索引: 332 GB

性能指标:

CASE 单次相似搜索响应速度 整机压测相似搜索TPS 整机压测相似搜索RT
10亿行,每行64个随机中文 40毫秒 428 149毫秒

CPU跑满,IO也蛮高

CPU耗费主要是bitmapscan, cpu进行tuple recheck造成。

IO耗费,主要是数据+索引已经接近600GB,超过了内存大小,涉及到大量的IO访问。

小结

1、PostgreSQL 11 , append 并行,使得性能有大幅度提升。

10亿条随机中文字符串(长度64)的相似搜索,耗时仅XXX秒。


1. postgres=# show enable_parallel_append ;
2. enable_parallel_append
3. ------------------------
4. on
5. (1 row)

2、本例子使用分区表的好处:

2.1、数据写入并行度提高,

2.2、创建索引变快,

2.3、维护索引也变快。

同时PostgreSQL 11已经支持多个分区并行扫描(enable_parallel_append),同时支持了并行+merge sort,所以海量数据相似搜索的大计算量情况下性能也不是问题。

在PostgreSQL 11之前,可以使用dblink异步调用来支持多个分区的并行扫描。例子:

《PostgreSQL dblink异步调用实现 并行hash分片JOIN - 含数据交、并、差 提速案例》

3、相似搜索中很关键的一个点是相似度,通过show_limit()可以查看相似度限制,通过set_limit可以设置相似度阈值。相似度值越大,表示需要的匹配度越高,1表示完全匹配。


1. postgres=# select show_limit();
2. show_limit
3. ------------
4. 0.3
5. (1 row)

7. postgres=# select set_limit(0.9);
8. set_limit
9. -----------
10. 0.9
11. (1 row)

4、通过similarity或word_similarity可以查看两个字符串的相似度值。


1. postgres=# select similarity('abc','abcd');
2. similarity
3. ------------
4. 0.5
5. (1 row)

7. postgres=# select word_similarity('abc','abcd');
8. word_similarity
9. -----------------
10. 0.75
11. (1 row)

13. postgres=# select word_similarity('abc','abc');
14. word_similarity
15. -----------------
16. 1
17. (1 row)

19. postgres=# select similarity('abc','abc');
20. similarity
21. ------------
22. 1
23. (1 row)

相似算法详情请参考

https://www.postgresql.org/docs/devel/static/pgtrgm.html

5、响应速度与用户设置的相似度有关,用户设置的相似度匹配到的值越多,速度越慢。匹配到的值越少(即精度越高),响应速度越快。


1. -- 响应速度更慢
2. postgres=# select set_limit(0.1);
3. set_limit
4. -----------
5. 0.1
6. (1 row)

8. -- 响应速度更快
9. postgres=# select set_limit(0.9);
10. set_limit
11. -----------
12. 0.9
13. (1 row)

实际生产中使用,我们可以先使用高的limit去搜索,逐渐缩小这个阈值,从而达到较快响应速度。这个逻辑可以封装到UDF中,用户调用UDF即可进行搜索。

例子


1. create or replace function get_res(
2. text,     -- 要按相似搜的文本
3. int8,     -- 限制返回多少条
4. float4 default 0.3,   -- 相似度阈值,低于这个值不再搜搜
5. float4 default 0.1    -- 相似度递减步长,直至阈值
6. ) returns setof record as $$
7. declare
8. lim float4 := 1;
9. begin
10. -- 判定
11. if not ($3 <= 1 and $3 > 0) then
12. raise notice '$3 must >0 and <=1';
13. return;
14. end if;

16. if not ($4 > 0 and $4 < 1) then
17. raise notice '$4 must >0 and <=1';
18. return;
19. end if;
20. loop
21. -- 设置相似度阈值
22. perform set_limit(lim);

24. return query select similarity(info, $1) as sml, * from tbl where info % $1 order by sml desc limit $2;

26. -- 如果有,则退出loop
27. if found then
28. return;
29. end if;

31. -- 否则继续,降低阈值
32. -- 当阈值小于0.3时,不再降阈值搜索,认为没有相似。
33. if lim < $3 then
34. return;
35. else
36. lim := lim - $4;
37. end if;
38. end loop;
39. end;
40. $$ language plpgsql strict;


1. select * from get_res('输入搜索文本', 输入限制条数, 输入阈值, 输入步长) as t(sml float4, id int, info text);

使用这个UDF搜索,既快又准。


1. postgres=# select * from get_res('四餧麾鄟賃青乖涢鰠揃擝垭岮操彴淒鋺約韉夗缝特鏋邜鯩垭縳墙靰禮徛亦猰庴釅恎噡鈛翱勜嘹雍岈', 10, 0.4, 0.05) as t(sml float4, id int, info text);
2. sml    | id |                                                               info
3. ----------+----+----------------------------------------------------------------------------------------------------------------------------------
4. 0.602941 |  1 | 彿睰掇贼展跃鬠唂四餧麾鄟賃青乖涢鰠揃擝垭岮操彴淒鋺約韉夗缝特鏋邜鯩垭縳墙靰禮徛亦猰庴釅恎噡鈛翱勜嘹雍岈擦寵淽蒸佊鴁糜婡籹侰亇浰鶙
5. (1 row)

7. Time: 75.957 ms

6、如果要设置PG实例、数据库、用户级的阈值,可以通过这两个参数来指定


1. pg_trgm.similarity_threshold

3. pg_trgm.word_similarity_threshold

他们分别作用于以下操作符和函数(详见 https://www.postgresql.org/docs/devel/static/pgtrgm.html )。


1. text % text
2. similarity(text, text)

4. 与

6. text <% text
7. word_similarity(text, text)

设置举例


1. postgres=# alter system set pg_trgm.similarity_threshold =0.9;
2. ALTER SYSTEM

4. postgres=# select pg_reload_conf();
5. pg_reload_conf
6. ----------------
7. t
8. (1 row)

10. -- 永久生效

12. postgres=# show pg_trgm.similarity_threshold;
13. pg_trgm.similarity_threshold
14. ------------------------------
15. 0.9
16. (1 row)

参考

《PostgreSQL 查询涉及分区表过多导致的性能问题 - 性能诊断与优化(大量BIND, spin lock, SLEEP进程)》

《PostgreSQL 商用版本EPAS(阿里云ppas) - 分区表性能优化 (堪比pg_pathman)》

《PostgreSQL 传统 hash 分区方法和性能》

《PostgreSQL 10 内置分区 vs pg_pathman perf profiling》

《PostgreSQL 10.0 preview 功能增强 - 内置分区表》

《PostgreSQL 全文检索之 - 位置匹配 过滤语法(例如 ‘速度 <1> 激情’)》

《PostgreSQL 模糊查询 与 正则匹配 性能差异与SQL优化建议》

《PostgreSQL 遗传学应用 - 矩阵相似距离计算 (欧式距离,…XX距离)》

《多流实时聚合 - 记录级实时快照 - JSON聚合与json全文检索的功能应用》

《PostgreSQL - 全文检索内置及自定义ranking算法介绍 与案例》

《用PostgreSQL 做实时高效 搜索引擎 - 全文检索、模糊查询、正则查询、相似查询、ADHOC查询》

《HTAP数据库 PostgreSQL 场景与性能测试之 17 - (OLTP) 数组相似查询》

《HTAP数据库 PostgreSQL 场景与性能测试之 16 - (OLTP) 文本特征向量 - 相似特征(海明…)查询》

《HTAP数据库 PostgreSQL 场景与性能测试之 14 - (OLTP) 字符串搜索 - 全文检索》

《HTAP数据库 PostgreSQL 场景与性能测试之 13 - (OLTP) 字符串搜索 - 相似查询》

《HTAP数据库 PostgreSQL 场景与性能测试之 12 - (OLTP) 字符串搜索 - 前后模糊查询》

《HTAP数据库 PostgreSQL 场景与性能测试之 9 - (OLTP) 字符串模糊查询 - 含索引实时写入》

《HTAP数据库 PostgreSQL 场景与性能测试之 7 - (OLTP) 全文检索 - 含索引实时写入》

《多国语言字符串的加密、全文检索、模糊查询的支持》

《Greenplum 模糊查询 实践》

《全文检索 不包含 优化 - 阿里云RDS PostgreSQL最佳实践》

《17种文本相似算法与GIN索引 - pg_similarity》

《PostgreSQL 模糊查询最佳实践 - (含单字、双字、多字模糊查询方法)》

《PostgreSQL 10.0 preview 功能增强 - JSON 内容全文检索》

《PostgreSQL结合余弦、线性相关算法 在文本、图片、数组相似 等领域的应用 - 3 rum, smlar应用场景分析》

《PostgreSQL结合余弦、线性相关算法 在文本、图片、数组相似 等领域的应用 - 2 smlar插件详解》

《PostgreSQL结合余弦、线性相关算法 在文本、图片、数组相似 等领域的应用 - 1 文本(关键词)分析理论基础 - TF(Term Frequency 词频)/IDF(Inverse Document Frequency 逆向文本频率)》

《导购系统 - 电商内容去重\内容筛选应用(实时识别转载\盗图\侵权?) - 文本、图片集、商品集、数组相似判定的优化和索引技术》

《PostgreSQL 全表 全字段 模糊查询的毫秒级高效实现 - 搜索引擎颤抖了》

《从难缠的模糊查询聊开 - PostgreSQL独门绝招之一 GIN , GiST , SP-GiST , RUM 索引原理与技术背景》

《从相似度算法谈起 - Effective similarity search in PostgreSQL》

《聊一聊双十一背后的技术 - 毫秒分词算啥, 试试正则和相似度》

《PostgreSQL 全文检索加速 快到没有朋友 - RUM索引接口(潘多拉魔盒)》

《PostgreSQL 文本数据分析实践之 - 相似度分析》

《中文模糊查询性能优化 by PostgreSQL trgm》

《PostgreSQL 行级 全文检索》

《PostgreSQL 百亿数据 秒级响应 正则及模糊查询》

《PostgreSQL chinese full text search 中文全文检索》

《聊一聊双十一背后的技术 - 毫秒分词算啥, 试试正则和相似度》

《PostgreSQL 1000亿数据量 正则匹配 速度与激情》

原文:http://mysql.taobao.org/monthly/2018/03/10/