os: centos 7.4
db: postgresql 10.11

版本

# cat /etc/centos-release
CentOS Linux release 7.4.1708 (Core)
#
#
# yum list installed |grep -i postgresql
postgresql10.x86_64                10.11-2PGDG.rhel7                   @pgdg10
postgresql10-contrib.x86_64        10.11-2PGDG.rhel7                   @pgdg10
postgresql10-debuginfo.x86_64      10.11-2PGDG.rhel7                   @pgdg10
postgresql10-devel.x86_64          10.11-2PGDG.rhel7                   @pgdg10
postgresql10-docs.x86_64           10.11-2PGDG.rhel7                   @pgdg10
postgresql10-libs.x86_64           10.11-2PGDG.rhel7                   @pgdg10
postgresql10-odbc.x86_64           12.00.0000-1PGDG.rhel7              @pgdg10
postgresql10-plperl.x86_64         10.11-2PGDG.rhel7                   @pgdg10
postgresql10-plpython.x86_64       10.11-2PGDG.rhel7                   @pgdg10
postgresql10-pltcl.x86_64          10.11-2PGDG.rhel7                   @pgdg10
postgresql10-server.x86_64         10.11-2PGDG.rhel7                   @pgdg10
postgresql10-tcl.x86_64            2.4.0-1.rhel7                       @pgdg10
postgresql10-tcl-debuginfo.x86_64  2.3.1-1.rhel7                       @pgdg10
postgresql10-test.x86_64           10.11-2PGDG.rhel7                   @pgdg10 # su - postgres
Last login: Wed Jan 15 18:34:12 CST 2020 on pts/0
$
$
$ psql -c "select version();"version
----------------------------------------------------------------------------------------------------------PostgreSQL 10.11 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-39), 64-bit
(1 row)

测试数据

postgres=# create table tmp_t0(id varchar(100),name1 varchar(100),name2 varchar(100));postgres=# create table tmp_t1(id varchar(100),name1 varchar(100),name2 varchar(100));postgres=#
postgres=# insert into tmp_t0
select id::varchar,md5(id::varchar),md5(md5(id::varchar)) from generate_series(1,5000000) as id;postgres=# insert into tmp_t1
select id::varchar,md5(id::varchar),md5(md5(id::varchar)) from generate_series(1,5000000) as id;

tmp_t0,tmp_t1 的 id 列上创建普通 btree 索引

postgres=# create index idx_tmp_t0_id on tmp_t0(id);postgres=# create index idx_tmp_t1_id on tmp_t1(id);postgres=# vacuum analyze tmp_t0;postgres=# vacuum analyze tmp_t1;

排除并行

postgres=# set max_parallel_workers_per_gather=0;

like ‘xxoo’

like ‘xxoo’ 等价于 = ‘xxoo’

postgres=# explain select t0.*,t1.* from tmp_t0 t0,tmp_t1 t1 where t0.id=t1.id and t0.id like '1000000';QUERY PLAN
--------------------------------------------------------------------------------------Nested Loop  (cost=0.86..16.91 rows=1 width=146)->  Index Scan using idx_tmp_t0_id on tmp_t0 t0  (cost=0.43..8.45 rows=1 width=73)Index Cond: ((id)::text = '1000000'::text)Filter: ((id)::text ~~ '1000000'::text)->  Index Scan using idx_tmp_t1_id on tmp_t1 t1  (cost=0.43..8.45 rows=1 width=73)Index Cond: ((id)::text = (t0.id)::text)
(6 rows)

like ‘xxoo%’

前模糊(有前缀的模糊)

postgres=# explain select t0.*,t1.* from tmp_t0 t0,tmp_t1 t1 where t0.id=t1.id and t0.id like '1000000%';QUERY PLAN
--------------------------------------------------------------------------------------Nested Loop  (cost=0.43..133262.84 rows=500 width=146)->  Seq Scan on tmp_t0 t0  (cost=0.00..129068.84 rows=500 width=73)Filter: ((id)::text ~~ '1000000%'::text)->  Index Scan using idx_tmp_t1_id on tmp_t1 t1  (cost=0.43..8.38 rows=1 width=73)Index Cond: ((id)::text = (t0.id)::text)
(5 rows)

可以看到 tmp_t0 走的是全表扫描(Seq Scan),并没有使用到索引。

查看文档(http://postgres.cn/docs/10/indexes-opclass.html )后发现 postgresql 并不会对 like ‘xxoo%’ 使用普通 btree 索引,看起来和 oracle 有差异。

新建个索引

postgres=# create index idx_tmp_t0_id_2 on tmp_t0(id varchar_pattern_ops);postgres=# vacuum analyze tmp_t0;
postgres=# explain select t0.*,t1.* from tmp_t0 t0,tmp_t1 t1 where t0.id=t1.id and t0.id like '1000000%';QUERY PLAN
----------------------------------------------------------------------------------------------Nested Loop  (cost=0.86..4202.45 rows=500 width=146)->  Index Scan using idx_tmp_t0_id_2 on tmp_t0 t0  (cost=0.43..8.45 rows=500 width=73)Index Cond: (((id)::text ~>=~ '1000000'::text) AND ((id)::text ~<~ '1000001'::text))Filter: ((id)::text ~~ '1000000%'::text)->  Index Scan using idx_tmp_t1_id on tmp_t1 t1  (cost=0.43..8.38 rows=1 width=73)Index Cond: ((id)::text = (t0.id)::text)
(6 rows)

可以看到已经使用了新建的 idx_tmp_t0_id_2 索引

like ‘%xxoo’

后模糊(有后缀的模糊)

postgres=# explain select t0.*,t1.* from tmp_t0 t0,tmp_t1 t1 where t0.id=t1.id and t0.id like '%1000000';QUERY PLAN
--------------------------------------------------------------------------------------Nested Loop  (cost=0.43..133264.25 rows=500 width=146)->  Seq Scan on tmp_t0 t0  (cost=0.00..129070.25 rows=500 width=73)Filter: ((id)::text ~~ '%1000000'::text)->  Index Scan using idx_tmp_t1_id on tmp_t1 t1  (cost=0.43..8.38 rows=1 width=73)Index Cond: ((id)::text = (t0.id)::text)
(5 rows)

没有使用到之前创建的 idx_tmp_t0_id,idx_tmp_t0_id_2 这两个索引。

这时需要新建个反转函数索引

postgres=# create index idx_tmp_t0_id_3 on tmp_t0(reverse(id) varchar_pattern_ops);postgres=# vacuum analyze tmp_t0;
postgres=# explain select t0.*,t1.* from tmp_t0 t0,tmp_t1 t1 where t0.id=t1.id and reverse(t0.id) like reverse('%1000000');QUERY PLAN
----------------------------------------------------------------------------------------------------------------Nested Loop  (cost=0.86..4202.46 rows=500 width=146)->  Index Scan using idx_tmp_t0_id_3 on tmp_t0 t0  (cost=0.43..8.46 rows=500 width=73)Index Cond: ((reverse((id)::text) ~>=~ '0000001'::text) AND (reverse((id)::text) ~<~ '0000002'::text))Filter: (reverse((id)::text) ~~ '0000001%'::text)->  Index Scan using idx_tmp_t1_id on tmp_t1 t1  (cost=0.43..8.38 rows=1 width=73)Index Cond: ((id)::text = (t0.id)::text)
(6 rows)

like ‘%xxoo%’

前后模糊(无前后缀的模糊)
3字或以上模糊查询,使用pg_trgm可以很好的解决。参考<<pg_trgm 处理中间匹配 like ‘%xxoo%’>>
pg_trgm 也能很好处理前后缀模糊的场景.

postgres=# create extension pg_trgm;postgres=# create index idx_tmp_t0_id_4 on tmp_t0 using gin(id gin_trgm_ops);
postgres=# explain select t0.*,t1.* from tmp_t0 t0,tmp_t1 t1 where t0.id=t1.id and t0.id like '%1000000%';QUERY PLAN
---------------------------------------------------------------------------------------Nested Loop  (cost=28.31..6094.51 rows=500 width=146)->  Bitmap Heap Scan on tmp_t0 t0  (cost=27.88..1900.51 rows=500 width=73)Recheck Cond: ((id)::text ~~ '%1000000%'::text)->  Bitmap Index Scan on idx_tmp_t0_id_4  (cost=0.00..27.75 rows=500 width=0)Index Cond: ((id)::text ~~ '%1000000%'::text)->  Index Scan using idx_tmp_t1_id on tmp_t1 t1  (cost=0.43..8.38 rows=1 width=73)Index Cond: ((id)::text = (t0.id)::text)
(7 rows)
postgres=# \d+ tmp_t0Table "public.tmp_t0"Column |          Type          | Collation | Nullable | Default | Storage  | Stats target | Description
--------+------------------------+-----------+----------+---------+----------+--------------+-------------id     | character varying(100) |           |          |         | extended |              | name1  | character varying(100) |           |          |         | extended |              | name2  | character varying(100) |           |          |         | extended |              |
Indexes:"idx_tmp_t0_id" btree (id)"idx_tmp_t0_id_2" btree (id varchar_pattern_ops)"idx_tmp_t0_id_3" btree (reverse(id::text) varchar_pattern_ops)"idx_tmp_t0_id_4" gin (id gin_trgm_ops)

like ‘%xxoo%’

1-2个字的模糊查询,优化器不会使用 pg_trgm 类型索引,可以创建个自定义函数索引。

postgres=# create or replace function f_user_split(text)
returns text[] as
$$
declareres text[];
beginselect regexp_split_to_array($1, '') into res;for i in 1..length($1)-1 loopres := array_append(res, substring($1, i, 2));end loop;return res;
end;
$$
language plpgsql strict immutable;
postgres=# create index idx_tmp_t0_id_5 on tmp_t0 using gin(f_user_split(id));postgres=# explain select t0.*,t1.* from tmp_t0 t0,tmp_t1 t1 where t0.id=t1.id and f_user_split(t0.id)  @> array['99'];QUERY PLAN
------------------------------------------------------------------------------------------------Hash Join  (cost=55802.50..191371.63 rows=25000 width=146)Hash Cond: ((t1.id)::text = (t0.id)::text)->  Seq Scan on tmp_t1 t1  (cost=0.00..116568.82 rows=5000082 width=73)->  Hash  (cost=55490.00..55490.00 rows=25000 width=73)->  Bitmap Heap Scan on tmp_t0 t0  (cost=241.75..55490.00 rows=25000 width=73)Recheck Cond: (f_user_split((id)::text) @> '{99}'::text[])->  Bitmap Index Scan on idx_tmp_t0_id_5  (cost=0.00..235.50 rows=25000 width=0)Index Cond: (f_user_split((id)::text) @> '{99}'::text[])
(8 rows)Time: 83.097 ms

参考:
http://postgres.cn/docs/10/indexes-opclass.html

postgresql 使用处理 like 'xxoo' 、like 'xxoo%' 、like '%xxoo'、like '%xxoo%'相关推荐

  1. 263企业邮箱在foxmail上的成功设置(smtpwcom/popwcom.xxoo.com)

    263企业邮箱在foxmail上设置了好几天,终于成功了! 长话短说,我使用的263邮箱没有以@263.com结尾的(化名@xxoo.com结尾),设置时不管使用smtp/pop.xxoo.com还是 ...

  2. postgresql 数据库出现 autovacuum:VACUUM xxoo.xxoo (to prevent wraparound)

    os: centos 7.4 db: postgresql 10.10 postgresql 查看 pg_stat_activity 有时会看到 autovacuum:VACUUM xxoo.xxoo ...

  3. 160630、五句话搞定JavaScript作用域

    JavaScript的作用域一直以来是前端开发中比较难以理解的知识点,对于JavaScript的作用域主要记住几句话,走遍天下都不怕.   一."JavaScript中无块级作用域" ...

  4. 五句话搞定JavaScript作用域【转】

    JavaScript的作用域一直以来是前端开发中比较难以理解的知识点,对于JavaScript的作用域主要记住几句话,走遍天下都不怕... 一."JavaScript中无块级作用域" ...

  5. 【html、CSS、javascript-8】JavaScript作用域

    JavaScript的作用域一直以来是前端开发中比较难以理解的知识点,对于JavaScript的作用域主要记住几句话 一.JavaScript中无块级作用域 在Java或C#中存在块级作用域,即:大括 ...

  6. 让你分分钟学会Javascript中的闭包

    Javascript中的闭包 前面的话: 闭包,是 javascript 中重要的一个概念,对于初学者来讲,闭包是一个特别抽象的概念,特别是ECMA规范给的定义,如果没有实战经验,你很难从定义去理解它 ...

  7. keepalived实现lvs高可用并负载均衡lamp

    一.安装lamp 1.安装httpd(172.16.23.211) [root@cs1 ~]# yum install -y httpd 2.安装php(172.16.23.211) [root@cs ...

  8. 来来来,一起五句话搞定JavaScript作用域

    JavaScript的作用域一直以来是前端开发中比较难以理解的知识点,对于JavaScript的作用域主要记住几句话,走遍天下都不怕... 一."JavaScript中无块级作用域" ...

  9. python123编写函数求和_Python基础之函数

    Python基础之函数 一.函数基础 1.函数概念: 函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可 2.函数的作用 (1)减少重复代码 (2)使程序变 ...

  10. AngularJS 表单数据验证及错误信息提示

    一.表单验证基本原理 表单验证包括两个主题: 定义验证规则,验证数据有效性. 显示验证结果,把验证结果以友好的方式显示给用户. H5内置一些验证功能,并会显示内置的错误提示信息,先要禁用它,在< ...

最新文章

  1. 面试官:不会看 Explain执行计划,简历敢写 SQL 优化?
  2. suse linux通过iso文件安装gcc
  3. LeetCode26. Remove Duplicates from Sorted Array
  4. vb6 datagrid表格垂直居中_Word文档中表格的定位方式
  5. Python 调用shell脚本
  6. JDBC+Servlet+JSP整合开发之22.JSP简介
  7. 【Python】SyntaxError: Non-ASCII character ‘\xe8‘ in file main.py on line 7, but no encoding declared;
  8. 【网络编程】同步、异步、阻塞和非阻塞
  9. 链接脚本(Linker Script)用法解析(一) 关键字SECTIONS与MEMORY
  10. Java方式实现上传微信素材
  11. 2021-02-10微软漏洞通告
  12. 微信公众平台数据统计
  13. 内存规格的解释(Unbuffered DIMM,Registered DIMM和SODIMM)
  14. 时间在线验证 java代码_timetest.java 源代码在线查看 - Java获取各种常用时间方法 资源下载 虫虫电子下载站...
  15. 还在用电脑多控手机?你out了,手机多控手机,全新神器
  16. 跟我StepByStep学FLEX教程------概述(原创)
  17. JqGrid 表格基本使用(一)
  18. 数据处理之seaborn的学习
  19. 测量工具----示波器
  20. 电力电子技术 学习总结1

热门文章

  1. EasyBoot制作启动光盘教程
  2. 小游戏,客户端游戏版号自助申请教程
  3. (未解决)SpringMVC学习——为什么网址不是locahost而是desktop-nottqjs(如图)
  4. word 插入目录及错误!未找到目录项
  5. 扬州工业机器人外壳设计排名_扬州模型达人设计机器人获奖
  6. select update delete
  7. dll控件安装方法(仅供参考)
  8. mysql判断字符串长度 超出用省略号_divcss超出长度文字自动隐藏或用省略号表示...
  9. 深入理解裸机与RTOS开发模式
  10. mysql密码expired_mysql密码过期的修改方法(your password has expired)