解读数仓常用模糊查询的优化方法
摘要:本文讲解了GaussDB(DWS)上模糊查询常用的性能优化方法,通过创建索引,能够提升多种场景下模糊查询语句的执行速度。
本文分享自华为云社区《GaussDB(DWS) 模糊查询性能优化》,作者: 黎明的风 。
在使用GaussDB(DWS)时,通过like进行模糊查询,有时会遇到查询性能慢的问题。
(一)LIKE模糊查询
通常的查询语句如下:
select * from t1 where c1 like 'A123%';
当表t1的数据量大时,使用like进行模糊查询,查询的速度非常慢。
通过explain查看该语句生成的查询计划:
test=# explain select * from t1 where c1 like 'A123%'; QUERY PLAN ----------------------------------------------------------------------------- id | operation | E-rows | E-memory | E-width | E-costs ----+------------------------------+--------+----------+---------+--------- 1 | -> Streaming (type: GATHER) | 1 | | 8 | 16.25 2 | -> Seq Scan on t1 | 1 | 1MB | 8 | 10.25 Predicate Information (identified by plan id) --------------------------------------------- 2 --Seq Scan on t1 Filter: (c1 ~~ 'A123%'::text)
查询计划显示对表t1进行了全表扫描,因此在表t1数据量大的时候执行速度会比较慢。
上面查询的模糊匹配条件 'A123%',我们称它为后模糊匹配。这种场景,可以通过建立一个BTREE索引来提升查询性能。
建立索引时需要根据字段数据类型设置索引对应的operator,对于text,varchar和char分别设置和text_pattern_ops,varchar_pattern_ops和bpchar_pattern_ops。
例如上面例子里的c1列的类型为text,创建索引时增加text_pattern_ops,建立索引的语句如下:
CREATE INDEX ON t1 (c1 text_pattern_ops);
增加索引后打印查询计划:
test=# explain select * from t1 where c1 like 'A123%'; QUERY PLAN ---------------------------------------------------------------------------------------- id | operation | E-rows | E-memory | E-width | E-costs ----+-----------------------------------------+--------+----------+---------+--------- 1 | -> Streaming (type: GATHER) | 1 | | 8 | 14.27 2 | -> Index Scan using t1_c1_idx on t1 | 1 | 1MB | 8 | 8.27 Predicate Information (identified by plan id) ---------------------------------------------------------------------- 2 --Index Scan using t1_c1_idx on t1 Index Cond: ((c1 ~>=~ 'A123'::text) AND (c1 ~<~ 'A124'::text)) Filter: (c1 ~~ 'A123%'::text)
在创建索引后,可以看到语句执行时会使用到前面创建的索引,执行速度会变快。
前面遇到的问题使用的查询条件是后缀的模糊查询,如果使用的是前缀的模糊查询,我们可以看一下查询计划是否有使用到索引。
test=# explain select * from t1 where c1 like '%A123'; QUERY PLAN ----------------------------------------------------------------------------- id | operation | E-rows | E-memory | E-width | E-costs ----+------------------------------+--------+----------+---------+--------- 1 | -> Streaming (type: GATHER) | 1 | | 8 | 16.25 2 | -> Seq Scan on t1 | 1 | 1MB | 8 | 10.25 Predicate Information (identified by plan id) --------------------------------------------- 2 --Seq Scan on t1 Filter: (c1 ~~ '%A123'::text)
如上图所示,当查询条件变成前缀的模糊查询,之前建的索引将不能使用到,查询执行时进行了全表的扫描。
这种情况,我们可以使用翻转函数(reverse),建立一个索引来支持前模糊的查询,建立索引的语句如下:
CREATE INDEX ON t1 (reverse(c1) text_pattern_ops);
将查询语句的条件采用reverse函数进行改写之后,输出查询计划:
test=# explain select * from t1 where reverse(c1) like 'A123%'; QUERY PLAN ------------------------------------------------------------------------------------------ id | operation | E-rows | E-memory | E-width | E-costs ----+-------------------------------+--------+----------+---------+--------- 1 | -> Streaming (type: GATHER) | 5 | | 8 | 14.06 2 | -> Bitmap Heap Scan on t1 | 5 | 1MB | 8 | 8.06 3 | -> Bitmap Index Scan | 5 | 1MB | 0 | 4.28 Predicate Information (identified by plan id) ---------------------------------------------------------------------------------------- 2 --Bitmap Heap Scan on t1 Filter: (reverse(c1) ~~ 'A123%'::text) 3 --Bitmap Index Scan Index Cond: ((reverse(c1) ~>=~ 'A123'::text) AND (reverse(c1) ~<~ 'A124'::text))
语句经过改写后,可以走索引, 查询性能得到提升。
(二)指定collate来创建索引
如果使用默认的index ops class时,要使b-tree索引支持模糊的查询,就需要在查询和建索引时都指定collate="C"。
注意:索引和查询条件的collate都一致的情况下才能使用索引。
创建索引的语句为:
CREATE INDEX ON t1 (c1 collate "C");
查询语句的where条件中需要增加collate的设置:
test=# explain select * from t1 where c1 like 'A123%' collate "C"; QUERY PLAN ---------------------------------------------------------------------------------------- id | operation | E-rows | E-memory | E-width | E-costs ----+-----------------------------------------+--------+----------+---------+--------- 1 | -> Streaming (type: GATHER) | 1 | | 8 | 14.27 2 | -> Index Scan using t1_c1_idx on t1 | 1 | 1MB | 8 | 8.27 Predicate Information (identified by plan id) ------------------------------------------------------------------ 2 --Index Scan using t1_c1_idx on t1 Index Cond: ((c1 >= 'A123'::text) AND (c1 < 'A124'::text)) Filter: (c1 ~~ 'A123%'::text COLLATE "C")
(三)GIN倒排索引
GIN(Generalized Inverted Index)通用倒排索引。设计为处理索引项为组合值的情况,查询时需要通过索引搜索出出现在组合值中的特定元素值。例如,文档是由多个单词组成,需要查询出文档中包含的特定单词。
下面举例说明GIN索引的使用方法:
create table gin_test_data(id int, chepai varchar(10), shenfenzheng varchar(20), duanxin text) distribute by hash (id); create index chepai_idx on gin_test_data using gin(to_tsvector('ngram', chepai)) with (fastupdate=on);
上述语句在车牌的列上建立了一个GIN倒排索引。
如果要根据车牌进行模糊查询,可以使用下面的语句:
select count(*) from gin_test_data where to_tsvector('ngram', chepai) @@ to_tsquery('ngram', '湘F');
这个语句的查询计划如下:
test=# explain select count(*) from gin_test_data where to_tsvector('ngram', chepai) @@ to_tsquery('ngram', '湘F'); QUERY PLAN ------------------------------------------------------------------------------------------------ id | operation | E-rows | E-memory | E-width | E-costs ----+------------------------------------------------+--------+----------+---------+--------- 1 | -> Aggregate | 1 | | 8 | 18.03 2 | -> Streaming (type: GATHER) | 1 | | 8 | 18.03 3 | -> Aggregate | 1 | 1MB | 8 | 12.03 4 | -> Bitmap Heap Scan on gin_test_data | 1 | 1MB | 0 | 12.02 5 | -> Bitmap Index Scan | 1 | 1MB | 0 | 8.00 Predicate Information (identified by plan id) ---------------------------------------------------------------------------------------------- 4 --Bitmap Heap Scan on gin_test_data Recheck Cond: (to_tsvector('ngram'::regconfig, (chepai)::text) @@ '''湘f'''::tsquery) 5 --Bitmap Index Scan Index Cond: (to_tsvector('ngram'::regconfig, (chepai)::text) @@ '''湘f'''::tsquery)
查询中使用了倒排索引,因此有比较的好的执行性能。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
彻底讲明白Java中眼花缭乱的各种并发锁
在互联网公司面试中,很多小伙伴都被问到过关于锁的问题。 今天,我给大家一次性把Java并发锁的全家桶彻底讲明白。包括互斥锁、读写锁、重入锁、公平锁、悲观锁、自旋锁、偏向锁等等等等。视频有点长,大家一定要全部看完,保证你会醍醐灌顶。 1、锁的由来 在并发编程中,经常会遇到两个以上的线程访问同一个共享变量,当同时对共享变量进行读写操作时,就会产生数据不一致的情况。 随着线程并发技术的发展,在多线程环境中,对线程访问资源的限制也越来越多。为了保证资源获取的有序性和占用性,都是通过并发锁来控制的。 2、锁的应用场景 下面,我根据个人经验以及并发场景下线程的处理逻辑,总结为以下7个场景,不同场景使用不同的锁。 1)某个线程是否锁住同步资源的情况 如果要锁住同步资源则使用悲观锁,不锁住同步资源使用乐观锁。 所谓悲观锁,就是每次拿数据的时候都认为会有别人修改,所以在读数据的时候都会上锁,其他线程数据就会阻塞,直到拿到锁。 举个例子,假设厕所只有一个坑位,悲观锁就是上厕所会第一时间把门反锁上,这样其他人上厕所只能在门外等候,这就是阻塞。 而乐观锁就是开着门,当然在这个场景下一般也不会这么做。所以,乐观...
- 下一篇
多表物化视图的设计与实现 | StarRocks 技术内幕
作者:StarRocks Committer 李雪岩,国双科技技术架构师、StarRocks Active Contributor 龚磊(本文为作者在 StarRocks Summit Asia 2022 上的分享) 本文先介绍物化视图的一些需求分析,看看现在的物化视图哪些地方做得好、哪些地方做得不好,然后再针对这些需求进行设计。然后再讲一下具体的实现原理,最后再讲一下 StarRocks 2.5 版本的物化视图还会开发哪些功能。 #01 物化视图的需求分析 — 1、什么是物化视图 要了解物化视图可以先了解视图的概念。视图是一个虚拟表(也可以认为是一条语句),基于它创建时指定的查询语句返回的结果集。而物化视图则是将这个虚拟表进行实体化,其本身可以理解为是一个特殊的表。 2、物化视图的应用场景 物化视图最常见的场景是,由基础的 Base 表通过创建物化视图的 SQL 生成物化视图,当用户查询相似的 SQL 时,查询优化器可以自动 QueryRewrite 复用物化视图,从而达到查询加速的效果。 在 2.4 之前,我们仅支持的是单表同步的物化视图,但它缺乏一些复杂场景的支持,例如只能...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2整合Redis,开启缓存,提高访问速度
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- MySQL8.0.19开启GTID主从同步CentOS8
- Mario游戏-低调大师作品
- Linux系统CentOS6、CentOS7手动修改IP地址
- Docker安装Oracle12C,快速搭建Oracle学习环境
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- CentOS7安装Docker,走上虚拟化容器引擎之路
- Docker快速安装Oracle11G,搭建oracle11g学习环境