PostgreSQL ADHoc(任意字段组合)查询(rums索引加速) - 非字典化,普通、数组等组合字段生成新数组

本文涉及的产品
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
RDS AI 助手,专业版
简介:

标签

PostgreSQL , rum 索引 , adhoc查询 , 非字典化 , 数组 , 普通字段 , 任意字段组合搜索


背景

《PostgreSQL ADHoc(任意字段组合)查询 与 字典化 (rum索引加速) - 实践与方案1》

这篇文档介绍了PostgreSQL AdHOC加速的原理,利用rum索引,精准搜索任意字段组合。10亿级数据,任意组合查询,RT低至毫秒级,TPS达到万级。文章提到了数据字典化,将多个字段转换为一个大数组,然后利用RUM索引加速的方法。

如果你嫌麻烦,可以有更加简单的方法,比如我们的表字段中本身就有普通字段,还有数组字段,多种组合,并且你不想字典化,然后有有任意字段组合的包含,相交,等值组合查询,(更复杂的ADhoc查询) 怎么办呢?

利用UDF,把要参与ADHOC(等值、包含、相交等组合条件)搜索的字段们组合起来,创建表达式RUM索引即可。

例子

1、测试表结构

create table test (    
  column1 varchar,    
  column2 int[],    
  column3 int[],    
  column4 text    
);    

目标

将数据转换为这样的数组

[column1_val, column2_val1, column2_val2,..., column3_val1, column3_val2,..., column4_val]    

然后针对这个数组来组合查询(利用rum索引精准搜索)。

2、创建一个函数,给数组添加前缀,返回一个TEXT数组

postgres=# create or replace function f_array_prefix(text, anyarray) returns text[] as $$    
  select array(select $1||unnest($2));              
$$ language sql strict immutable;    

效果

postgres=# select f_array_prefix('abc_', array[1,2,3]);    
   f_array_prefix        
---------------------    
 {abc_1,abc_2,abc_3}    
(1 row)    
    
postgres=# select f_array_prefix('abc_', array['a','b','c']);    
   f_array_prefix        
---------------------    
 {abc_a,abc_b,abc_c}    
(1 row)    

2.1、扩展知识,解读一个带前缀的数组的指定前缀的后缀。

postgres=# create or replace function get_suffix(text[], text) returns text[] as $$
  select array_remove(array(select substring(unnest, $2||'(.*)') from unnest($1)),null);
$$ language sql strict immutable;
CREATE FUNCTION

postgres=# select get_suffix(array['abc_1','abc_2','t_2','t_123'], 't_');
 get_suffix 
------------
 {2,123}
(1 row)

3、创建表达式函数,将test表参与ADHoc查询的字段们组合成一个新的TEXT数组

create or replace function f_search(varchar, int[], int[], text) returns text[] as $$    
  select 
  array_remove(    
    array_append(    
      array_cat(    
        array_cat(    
          array_append(array[]::text[], 'column1_'||$1), -- 初始数组为空     
          f_array_prefix('column2_', $2)    
        ),    
        f_array_prefix('column3_', $3)    
      ),    
      'column4_'||$4     
    ),
  null);    
$$ language sql CALLED ON NULL INPUT immutable;    

效果

postgres=# select f_search('abcde', array[1,2,3], array[5,6,7], 'hello');    
                                         f_search                                              
-------------------------------------------------------------------------------------------    
 {column1_abcde,column2_1,column2_2,column2_3,column3_5,column3_6,column3_7,column4_hello}    
(1 row)    

4、创建一个函数,生成随机数组:1万个取值空间, 20个随机值.

create or replace function gen_rand() returns int[] as $$    
  select array(select (10000*random())::int from generate_series(1,20));    
$$ language sql strict volatile;    

效果

postgres=# select gen_rand();    
                                              gen_rand                                                  
----------------------------------------------------------------------------------------------------    
 {6714,935,1593,8801,4097,5959,2059,3306,8710,4663,8671,7999,9122,4405,8874,236,822,6524,8093,8368}    
(1 row)    
    
postgres=# select gen_rand();    
                                               gen_rand                                                    
-------------------------------------------------------------------------------------------------------    
 {3640,5125,5307,4672,1943,9987,6141,8813,6347,6007,9652,3061,6942,1245,1862,1039,7204,3921,4345,5914}    
(1 row)    

5、生成100万测试数据

insert into test select md5(random()::text), gen_rand(), gen_rand(), md5(random()::text) from generate_series(1,1000000);    

6、创建表达式rum索引

create index idx_test_1 on test using rum (f_search(column1, column2, column3, column4) rum_anyarray_ops);    

7、表和索引大小如下

postgres=# \dt+ test    
                    List of relations    
 Schema | Name | Type  |  Owner   |  Size  | Description     
--------+------+-------+----------+--------+-------------    
 public | test | table | postgres | 287 MB |     
(1 row)    
    
postgres=# \di+ idx_test_1     
                           List of relations    
 Schema |    Name    | Type  |  Owner   | Table |  Size  | Description     
--------+------------+-------+----------+-------+--------+-------------    
 public | idx_test_1 | index | postgres | test  | 917 MB |     
(1 row)    

8、对等查询例子

explain select * from test where f_search(column1, column2, column3, column4) @> array['column2_1', 'column3_5'];    
    
等价于    
    
explain select * from test where column2 @> array[1] and column3 @> array[5];    
explain select * from test where f_search(column1, column2, column3, column4) && array['column2_1', 'column3_5'];    
    
等价于    
    
explain select * from test where column2 @> array[1] or column3 @> array[5];    
explain select * from test     
where     
f_search(column1, column2, column3, column4) @> array['column2_1', 'column3_5', 'column1_abc']    
or    
f_search(column1, column2, column3, column4) @> array['column2_2', 'column3_5', 'column1_abc']    
or    
f_search(column1, column2, column3, column4) @> array['column2_3', 'column3_5', 'column1_abc'];    
    
等价于    
    
explain select * from test where column2 && array[1,2,3] and column3 @> array[5] and column1='abc';    

9、例子

任意字段组合, 精准检索,1毫秒内响应。

postgres=# explain (analyze,verbose,timing,costs,buffers)   
select * from test   
where   -- 表达式查询  
f_search(column1, column2, column3, column4) @> array['column2_1', 'column3_5'];    
  
                                                          QUERY PLAN                                                              
------------------------------------------------------------------------------------------------------------------------------    
 Index Scan using idx_test_1 on public.test  (cost=12.00..43.64 rows=25 width=268) (actual time=0.511..0.530 rows=10 loops=1)    
   Output: column1, column2, column3, column4    
   Index Cond: (f_search(test.column1, test.column2, test.column3, test.column4) @> '{column2_1,column3_5}'::text[])    
   Buffers: shared hit=20    
 Planning Time: 0.245 ms    
 Execution Time: 0.548 ms    
(6 rows)    

深挖优化 - schema less\分区

如果你的数据中,有一些字段很稀疏,并且这些字段也参与了任意字段组合搜索,那么有没有更深入的优化方法呢?

稀疏列的查看

analyze tablename;
select attname, n_distinct from pg_stats where tablename='tablename' and n_distinct>=0 order by 2;

我们有两种方法可以使得性能更加精进:

1、对这些稀疏字段采用schema less\表分区,就是说通过UDF或者数据库的多级分区表,将数据按稀疏字段打散,每个分区一个RUM索引(分区字段不作为RUM的索引字段),当输入分区字段作为组合查询条件时,会自动根据分区规则过滤到对应的一个或多个分区进行查询。

2、对RUM索引使用partial index或(分区索引),与方法1类似,只不过是一张表,但是通过partial index手段对索引进行分区,实现索引本身的切片,当任意字段搜索中输入了partial index的where 字段条件时,自动选择对应的RUM partial索引。

但是,请注意:

如果用户没有输入任何分区字段作为条件,那么需要扫描所有分区,每个分区走对应的分区RUM索引。

方法1例子:

《时间、空间、对象多维属性 海量数据任意多维 高效检索 - 阿里云RDS PostgreSQL最佳实践》

《PostgreSQL 在铁老大订单系统中的schemaless设计和性能压测》

《PostgreSQL schemaless 的实现(类mongodb collection)》

《PostgreSQL 时序最佳实践 - 证券交易系统数据库设计 - 阿里云RDS PostgreSQL最佳实践》

深挖优化 - partial index\分区索引

方法2例子:

《PostgreSQL 店铺运营实践 - JSON[]数组 内部标签数据等值、范围检索100倍+加速示例 (含,单值+多值列合成)》

《PostgreSQL UDF实现tsvector(全文检索), array(数组)多值字段与scalar(单值字段)类型的整合索引(类分区索引) - 单值与多值类型复合查询性能提速100倍+ 案例 (含,单值+多值列合成)》

小结

本文提供了一种简单的方法,将包括若干普通字段、数组字段的adhoc查询简化,不需要字典化,就可以利用RUM索引,进行非常高效率的精准检索。

参考

《PostgreSQL ADHoc(任意字段组合)查询 与 字典化 (rum索引加速) - 实践与方案1》

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

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

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

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

相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍如何基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
目录
相关文章
|
7月前
|
存储 监控 关系型数据库
B-tree不是万能药:PostgreSQL索引失效的7种高频场景与破解方案
在PostgreSQL优化实践中,B-tree索引虽承担了80%以上的查询加速任务,但因多种原因可能导致索引失效,引发性能骤降。本文深入剖析7种高频失效场景,包括隐式类型转换、函数包裹列、前导通配符等,并通过实战案例揭示问题本质,提供生产验证的解决方案。同时,总结索引使用决策矩阵与关键原则,助你让索引真正发挥作用。
493 0
|
SQL 数据库
LangChain-09 Query SQL DB With RUN GPT 查询数据库 并 执行SQL 返回结果
LangChain-09 Query SQL DB With RUN GPT 查询数据库 并 执行SQL 返回结果
186 2
|
监控 关系型数据库 数据库
PostgreSQL的索引优化策略?
【8月更文挑战第26天】PostgreSQL的索引优化策略?
541 1
|
机器学习/深度学习 SQL 数据挖掘
ADB优化器背后的秘密:如何用成本估算和规则引擎编织高效的查询网络?
【8月更文挑战第27天】AnalyticDB (ADB) 是一款专为大规模数据集设计的高性能分析型数据库。本文深入探讨ADB的优化器如何通过成本估算、规则引擎及机器学习等策略生成高效执行计划。成本估算是选择最优路径的关键;规则引擎通过谓词下推等手段优化查询;机器学习则使优化器能基于历史数据预测执行效率。结合示例代码与执行计划分析,展现了ADB在提升查询性能方面的强大功能。未来,ADB将继续进化以满足日益增长的大数据分析需求。
301 0
|
11月前
|
SQL 关系型数据库 OLAP
云原生数据仓库AnalyticDB PostgreSQL同一个SQL可以实现向量索引、全文索引GIN、普通索引BTREE混合查询,简化业务实现逻辑、提升查询性能
本文档介绍了如何在AnalyticDB for PostgreSQL中创建表、向量索引及混合检索的实现步骤。主要内容包括:创建`articles`表并设置向量存储格式,创建ANN向量索引,为表增加`username`和`time`列,建立BTREE索引和GIN全文检索索引,并展示了查询结果。参考文档提供了详细的SQL语句和配置说明。
414 2
|
12月前
|
JSON 关系型数据库 PostgreSQL
PostgreSQL 9种索引的原理和应用场景
PostgreSQL 支持九种主要索引类型,包括 B-Tree、Hash、GiST、SP-GiST、GIN、BRIN、Bitmap、Partial 和 Unique 索引。每种索引适用于不同场景,如 B-Tree 适合范围查询和排序,Hash 仅用于等值查询,GiST 支持全文搜索和几何数据查询,GIN 适用于多值列和 JSON 数据,BRIN 适合非常大的表,Bitmap 适用于低基数列,Partial 只对部分数据创建索引,Unique 确保列值唯一。
1136 15
|
SQL 数据库
LangChain-08 Query SQL DB 通过GPT自动查询SQL
LangChain-08 Query SQL DB 通过GPT自动查询SQL
209 3
|
关系型数据库 MySQL 数据库
Python MySQL查询返回字典类型数据的方法
通过使用 `mysql-connector-python`库并选择 `MySQLCursorDict`作为游标类型,您可以轻松地将MySQL查询结果以字典类型返回。这种方式提高了代码的可读性,使得数据操作更加直观和方便。上述步骤和示例代码展示了如何实现这一功能,希望对您的项目开发有所帮助。
536 4
|
SQL 关系型数据库 MySQL
SQL Server、MySQL、PostgreSQL:主流数据库SQL语法异同比较——深入探讨数据类型、分页查询、表创建与数据插入、函数和索引等关键语法差异,为跨数据库开发提供实用指导
【8月更文挑战第31天】SQL Server、MySQL和PostgreSQL是当今最流行的关系型数据库管理系统,均使用SQL作为查询语言,但在语法和功能实现上存在差异。本文将比较它们在数据类型、分页查询、创建和插入数据以及函数和索引等方面的异同,帮助开发者更好地理解和使用这些数据库。尽管它们共用SQL语言,但每个系统都有独特的语法规则,了解这些差异有助于提升开发效率和项目成功率。
1745 0
|
SQL Cloud Native 关系型数据库
ADBPG(AnalyticDB for PostgreSQL)是阿里云提供的一种云原生的大数据分析型数据库
ADBPG(AnalyticDB for PostgreSQL)是阿里云提供的一种云原生的大数据分析型数据库
1968 1

相关产品

  • 云原生数据库 PolarDB
  • 云数据库 RDS PostgreSQL 版
  • 推荐镜像

    更多