postgresql 使用处理 like 'xxoo' 、like 'xxoo%' 、like '%xxoo'、like '%xxoo%'
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%'相关推荐
- 263企业邮箱在foxmail上的成功设置(smtpwcom/popwcom.xxoo.com)
263企业邮箱在foxmail上设置了好几天,终于成功了! 长话短说,我使用的263邮箱没有以@263.com结尾的(化名@xxoo.com结尾),设置时不管使用smtp/pop.xxoo.com还是 ...
- postgresql 数据库出现 autovacuum:VACUUM xxoo.xxoo (to prevent wraparound)
os: centos 7.4 db: postgresql 10.10 postgresql 查看 pg_stat_activity 有时会看到 autovacuum:VACUUM xxoo.xxoo ...
- 160630、五句话搞定JavaScript作用域
JavaScript的作用域一直以来是前端开发中比较难以理解的知识点,对于JavaScript的作用域主要记住几句话,走遍天下都不怕. 一."JavaScript中无块级作用域" ...
- 五句话搞定JavaScript作用域【转】
JavaScript的作用域一直以来是前端开发中比较难以理解的知识点,对于JavaScript的作用域主要记住几句话,走遍天下都不怕... 一."JavaScript中无块级作用域" ...
- 【html、CSS、javascript-8】JavaScript作用域
JavaScript的作用域一直以来是前端开发中比较难以理解的知识点,对于JavaScript的作用域主要记住几句话 一.JavaScript中无块级作用域 在Java或C#中存在块级作用域,即:大括 ...
- 让你分分钟学会Javascript中的闭包
Javascript中的闭包 前面的话: 闭包,是 javascript 中重要的一个概念,对于初学者来讲,闭包是一个特别抽象的概念,特别是ECMA规范给的定义,如果没有实战经验,你很难从定义去理解它 ...
- keepalived实现lvs高可用并负载均衡lamp
一.安装lamp 1.安装httpd(172.16.23.211) [root@cs1 ~]# yum install -y httpd 2.安装php(172.16.23.211) [root@cs ...
- 来来来,一起五句话搞定JavaScript作用域
JavaScript的作用域一直以来是前端开发中比较难以理解的知识点,对于JavaScript的作用域主要记住几句话,走遍天下都不怕... 一."JavaScript中无块级作用域" ...
- python123编写函数求和_Python基础之函数
Python基础之函数 一.函数基础 1.函数概念: 函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可 2.函数的作用 (1)减少重复代码 (2)使程序变 ...
- AngularJS 表单数据验证及错误信息提示
一.表单验证基本原理 表单验证包括两个主题: 定义验证规则,验证数据有效性. 显示验证结果,把验证结果以友好的方式显示给用户. H5内置一些验证功能,并会显示内置的错误提示信息,先要禁用它,在< ...
最新文章
- 面试官:不会看 Explain执行计划,简历敢写 SQL 优化?
- suse linux通过iso文件安装gcc
- LeetCode26. Remove Duplicates from Sorted Array
- vb6 datagrid表格垂直居中_Word文档中表格的定位方式
- Python 调用shell脚本
- JDBC+Servlet+JSP整合开发之22.JSP简介
- 【Python】SyntaxError: Non-ASCII character ‘\xe8‘ in file main.py on line 7, but no encoding declared;
- 【网络编程】同步、异步、阻塞和非阻塞
- 链接脚本(Linker Script)用法解析(一) 关键字SECTIONS与MEMORY
- Java方式实现上传微信素材
- 2021-02-10微软漏洞通告
- 微信公众平台数据统计
- 内存规格的解释(Unbuffered DIMM,Registered DIMM和SODIMM)
- 时间在线验证 java代码_timetest.java 源代码在线查看 - Java获取各种常用时间方法 资源下载 虫虫电子下载站...
- 还在用电脑多控手机?你out了,手机多控手机,全新神器
- 跟我StepByStep学FLEX教程------概述(原创)
- JqGrid 表格基本使用(一)
- 数据处理之seaborn的学习
- 测量工具----示波器
- 电力电子技术 学习总结1
热门文章
- EasyBoot制作启动光盘教程
- 小游戏,客户端游戏版号自助申请教程
- (未解决)SpringMVC学习——为什么网址不是locahost而是desktop-nottqjs(如图)
- word 插入目录及错误!未找到目录项
- 扬州工业机器人外壳设计排名_扬州模型达人设计机器人获奖
- select update delete
- dll控件安装方法(仅供参考)
- mysql判断字符串长度 超出用省略号_divcss超出长度文字自动隐藏或用省略号表示...
- 深入理解裸机与RTOS开发模式
- mysql密码expired_mysql密码过期的修改方法(your password has expired)