基于开发者空间OpenGauss数据库列存引擎的分析与使用

1 概述

1.1 案例介绍

OpenGaussDB的Cstore列存引擎是用于OLAP分析型业务场景,主要应用于大数据量的数据分析,数据汇聚运算,用于决策业务系统使用。但近年来由于AI应用和大模型的发展。AI训练需要大量数据为基础,而AI的训练数据的读取和计算特点都属于OLAP业务场景。故AI使用的非结构向量数据通常也采用列存数据库进行存储。

通过实际操作,让大家深入了解如何利用OpenGaussDB开发并部署一个AI服务Dify。在这个过程中,大家将学习到从OpenGauss官方网站使用Cstore和DataVec数据引擎等一系列关键步骤,从而掌握列式存储表的基本使用方法,体验其在应用开发中的优势。

1.2 适用对象

  • 企业
  • 个人开发者
  • 高校学生

1.3 案例时间

本案例总时长预计30分钟。

1.4 案例流程

1bffead9d6728b8f21b713686d553010.png{{{width="55%" height="auto"}}}

说明:

  1. 领取空间开发桌面,登录云主机;
  2. 在云主机终端进入OpenGaussDB;
  3. 进入开发者空间部署OpenGaussDB数据库之列存引擎和向量引擎应用;

1.5 资源总览

资源名称规格单价(元)时长(分钟)
开发者空间-云主机ARM架构, | 4 vCPUs | 8 GB | OpenEuler 22.03 Server定制版 (40GB)免费30

2 CSTORE列存引擎

2.1 开发者空间配置

面向广大开发者群体,华为开发者空间提供一个随时访问的“开发桌面云主机”、丰富的“预配置工具集合”和灵活使用的“场景化资源池”,开发者开箱即用,快速体验华为根技术和资源。

如果还没有领取开发者空间云主机,可以参考免费领取云主机文档领取。

领取云主机后可以直接进入华为开发者空间工作台界面,点击打开云主机 > 进入桌面连接云主机。

a1aae6ff53aac98855ef597dd6899967.png

552fc96c3b58a06e294e4a760ae719e3.PNG

2.2 启动OpenGaussDB实例并登录

本案例中,使用OpenGaussDB开发平台,完成SQL的编程和自定义函数等多种功能。

基于之前案例《基于开发者空间部署OpenGauss主备集中式数据库系统》。在云主机部署OpenGaussDB实例。并启动数据库服务。

进入OpenGaussDB的安装目录的bin文件,该案例云主机环境中安装目录在环境变量\$GAUSSHOME中,读者根据自己云主机安装目录进行操作修改。

cd $GAUSSHOME/bin

初始化数据库实例,初始化数据库目录在当前目录下data,设置节点名称和初始化用户密码。如下所示

./gs_initdb -D data --nodename=n1 -w GaussDB@123

bc4c9086cc4dbb1598050419cec476da.png

以单节点模式启动数据库实例,并在当前目录下输出日志文件logfile

./gs_ctl start -D data -Z single_node -l logfile

0f652e9f9eee07b00cb8516f34ad694d.png

用gsql客户端工具,进入OpenGaussDB数据库。参数 -a表示追加、-r表示使用readline

./gsql -d postgres -ar

17fd3a6e9547f144785194c54de16c3d.png

2.3 Cstore 列式存储

f9cbef9ff363a1d89fe6b915b931ce9d.png

与行存储格式不同,列式存储以每个字段的数据为单元进行存储,由于每个存储单元的数据都属于表的一个字段,所以该单元里的数据类型是一样的,更有利于压缩存储,并且面向大数据表时,如果一个select查询的投影只有大表的少量字段,则列存表在查询性能上更有优势,所以Cstore引擎更适合OLAP分析型业务场景。由于列存引擎多数用于OLAP,所以其在聚合函数和MERGE操作上有更多的优化空间,其性能也远比行存效率高。

Cstore列存储的主体数据文件以CU为I/O单元,只支持追加写操作,因此cstore只有读共享缓冲区。CU间和CU内的可见性由对应的CUDESE表(astore表)决定,因此其可见性和并发控制原理与行存储astore基本相同。

cstore列存储格式整体框架如下:

06c128504329ad5e5e51431e5b406171.png

2.3.1 Cstore的存储单元结构

如图所述,cstore的存储单元是CU,分别包括以下内容。

77885b019d7d9c4c1d6716fb69ddd8ae.png

  • CU的CRC值,为CU结构中除CRC成员外,其他所有字节计算出的32位CRC值。
  • CU的magic值,为插入CU的事务号。
  • CU的属性值,为16位标志值,包括CU是否包含NULL行、CU使用的压缩算法等CU粒度属性信息。
  • 压缩后NULL值位图长度,如果属性值中标识该CU包含NULL行,则本CU在实际数据内容开始处包含NULL值位图,此处存储该位图的字节长度,如果该CU不包含NULL行,则无该成员。
  • 压缩前数据长度,即CU数据内容在压缩前的字节长度,用于读取CU时进行内存申请和校验。
  • 压缩后数据长度,即CU数据内容在压缩后的字节长度,用于插入CU时进行内存申请和校验。
  • 压缩后NULL值位图内容,如果属性值中标识该CU包含NULL行,则该成员即为每行的NULL值位图,否则无该成员。
  • 压缩后数据内容,即实际写入磁盘的CU主体数据内容。

每个CU最多保存对应字段的MAX_BATCH_ROWS行(默认60000行)数据。相邻CU之间按8KB对齐。

c2885f7aa12f3d5c6f9a17dd997c0b84.png

2.3.2 列存表限制与相关参数

限制:

  • 列存表不支持数组。
  • 列存表的数量建议不超过 1000 个。
  • 列存表的表级约束只支持 PARTIAL CLUSTER KEY,不支持主外键等表级约束。
  • 列存表的字段约束只支持 NULL、NOT NULL 和 DEFAULT 常量值。
  • 列存表不支持 alter 命令修改字段约束。
  • 列存表支持 delta 表,受参数 enable_delta_store 控制是否开启,受参数 deltarow_threshold 控制进入 delta 表的阀值。

列存相关参数:

  • cstore_buffers

列存所使用的共享缓冲区的大小,默认值:32768KB

  • partition_mem_batch

指定缓存个数,为了优化对列存分区表的批量插入,在批量插入过程中会对数据进行缓存后再批量写盘。默认值:256

  • partition_max_cache_size

指定数据缓存区大小,为了优化对列存分区表的批量插入,在批量插入过程中会对数据进行缓存后再批量写盘。默认值:2GB

  • enable_delta_store

为了增强列存单条数据导入的性能和解决磁盘冗余问题,是否需要开启列存 delta 表功能,与参数 DELTAROW_THRESHOLD 配合使用。默认值:off

2.3.3 cstore表实践

语法格式

CREATE TABLE table_name 
    (column_name data_type [, ... ])
    [ WITH ( ORIENTATION  = value) ];

参数说明:

table_name:要创建的表名。

column_name:新表中要创建的字段名。

data_type:字段的数据类型。

ORIENTATION:指定表数据的存储方式,即行存方式,列存方式,该参数设置成功后就不再支持修改。

取值范围:

ROW:表示表的数据将以行式存储。行存储适合于OLTP业务,适用于点查询或者增删操作较多的场景,目前使用ASTORE,USTORE作为行存储引擎。

COLUMN:表示表的数据将以列式存储。列存储适合于数据仓库业务,此类型的表上会做大量的汇聚计算,且涉及的列操作较少,目前使用Cstore作为列存储引擎。

首先在postgres.conf里添加参数enable_delta_store = on

(postgres.conf在数据目录data下,data目录根据initdb初始化设置的路径有关,一般在\$GAUSSHOME/bin目录下)

0cc9f1b4ba89467ecdc25bf7266d7dba.png

然后重启数据库服务

cd $GAUSSHOME/bin
gs_ctl -D data/ restart
gsql -d postgres -ar
-- 如果gs_ctl启动数据库服务时,找不到对应动态库,则添加下环境变量
export LD_LIBRARY_PATH=$GAUSSHOME/lib:$LD_LIBRARY_PATH

不指定ORIENTATION参数时,表默认为行存表。例如:

CREATE TABLE customer_test1
(
  state_ID   CHAR(2),
  state_NAME VARCHAR2(40),
  area_ID    NUMBER
);
\d+ customer_test1
--删除表
DROP TABLE customer_test1;

4cdaaf895bfedb9d93f92cd9ac6ce9ff.png

创建列存表时,需要指定ORIENTATION参数。例如:

CREATE TABLE customer_test2
(
  state_ID   CHAR(2),
  state_NAME VARCHAR2(40),
  area_ID    NUMBER
)
WITH (ORIENTATION = COLUMN);
\d+ customer_test2

--删除表
DROP TABLE customer_test2;

ad065f38f11fb6a7e75264cc6cc924af.png

行存表与列存表对比实践:

\dt
-- 创建行存表,压缩和不压缩的两张表
create table test_t(id serial primary key ,col1 varchar(8),col2 decimal(6,2),create_time timestamptz not null default now());
\dt+
-- 创建列存表
create table column_t(id serial,col1 varchar(8),col2 decimal(6,2),create_time timestamptz not null default now()) with (orientation=column );
create table column_th(id serial,col1 varchar(8),col2 decimal(6,2),create_time timestamptz not null default now()) with (orientation=column ,compression=high);
create table column_tm(id serial,col1 varchar(8),col2 decimal(6,2),create_time timestamptz not null default now()) with (orientation=column ,compression=middle);
\dt+
-- 列存表添加局部聚簇存储列
alter table column_t add PARTIAL CLUSTER KEY(id);
\d+ column_t

456817386808f3dcecab53ec3442b283.png

580cffb2b982713b948f4ab01b54926e.png

8d4402b7a8f4815f73a56359bd2df822.png

磁盘使用空间对比:分别向两个表插入100万条数据,占比磁盘大小对比

\timing
insert into column_t select generate_series(1,1000000),left(md5(random()::text),8),random()::numeric(6,2);
insert into column_th select generate_series(1,1000000),left(md5(random()::text),8),random()::numeric(6,2);
insert into column_tm select generate_series(1,1000000),left(md5(random()::text),8),random()::numeric(6,2);
insert into test_t select generate_series(1,1000000),left(md5(random()::text),8),random()::numeric(6,2);
\dt+

0a252b7a5ff2e3e46736c638aee27a77.png

列存表开启的压缩级别越高占用磁盘空间越少。

列存表占用磁盘空间比行存表占用磁盘空间少近5\~7倍。

DML对比:查找单列

select col1 from test_t where id>=100010 and id<100020;
select col1 from column_t where id>=100010 and id<100020;

e7e6276fe41c1a0db87eb08b52522a1c.png

DML对比:随机查找

select col1 from test_t limit 10;
select col1 from column_t limit 10;

9684eca9ba7c8b561e8a5c4575ae8906.png

DML对比:select * 查询对比,行存表比列存表快近5倍

select * from test_t limit 10;
select * from column_t limit 10;

3d7edc71e4480f7e17a161391a64159b.png

DML对比:Update操作,列存比行存快近12倍

update test_t set col1=col1;
update column_t set col1=col1;

be9d797ee4ad150d906aeebe50da4abf.png

结论:

列存表比行存表在磁盘空间占用上节省近 5\~7 倍。

查询指定字段,列存表比行存表慢约 4 倍。(可能是数据解压缩,因为数据都在缓存中,行存表没有压缩,列存表数据有压缩,查询时需要解压缩耗时,数据量越大,解压数据耗时越多)

select * 的方式,列存表比行存表慢 80%。

默认压缩方式批量导入数据,列存表比行存表快 100%。

注:

目前AI和大模型训练,需要大量数据投喂,所以用于存储多维向量非结构化数据的数据库成为发展重点。而AI运算多为浮点数据,主要用于相似性搜索。比如在高维空间里找最近的邻近数据,通常只涉及向量字段和少量过滤条件。这对于ai大模型训练时的大规模和高性能相似性搜索决定其数据存储必然是列存引擎。列存数据库在高维数据的读取效率、计算密集性以及存储成本有着比行存天然的优势。

AI和大模型训练数据,具备特点:

  • 只读取所需的部分列(列存极大减少i/o操作量)。
  • 同质数据的高效数据压缩(更小的存储空间和更快的磁盘i/o)。
  • 向量化计算和SIMD并行计算优化,需要批处理同列数据,列存引擎在此方面加速了核心的相似性计算(距离计算,内积计算)。
  • 列存更适合过滤和聚合运算,加速了带过滤条件的混合查询,也是AI训练使用数据时常用查询操作。
  • 向量数据库的查询模式本质上是OLAP分析型业务,特点通常是读密集型,写入与更新操作相对较少。

3 DataVec向量数据库引擎

openGauss DataVec 向量数据库是一个基于openGauss的向量引擎, 提供向量数据类型的存储、检索。在处理大规模高维向量数据时,能够提供快速、准确的检索结果。适用于智能知识检索、 检索增强生成 RAG(Retrieval-Augmented Generation) 等各种复杂应用场景的智能应用。

DataVec目前支持的向量功能有:精确和近似的最近邻搜索、L2距离&余弦距离&内积、向量索引、向量操作函数和操作符。作为openGauss的内核特性,DataVec使用熟悉的SQL语法操作向量,简化了用户使用向量数据库的过程。

3.1 特性描述

DataVec能够无缝对接自研大模型。通过嵌入技术将非结构化数据(如文本、图像等)转换为向量数据,DataVec为之提供存储和检索能力。嵌入是一种将非结构化数据映射到向量空间的技术,使得相似文本、图像在向量空间中的距离相近,从而提高检索的准确性和效率。

此外,DataVec还支持鲲鹏指令集加速,实现毫秒级响应。鲲鹏指令集是华为自主研发的一套高性能计算指令集,能够显著提升数据处理和计算的效率。通过利用鲲鹏指令集,DataVec可以在处理大规模向量数据时,提供更快的响应速度和更高的处理能力。

在实际应用中,DataVec可以广泛应用于各种需要高效向量检索的场景。例如,在推荐系统中,DataVec可以根据用户的历史行为和偏好,快速找到与用户兴趣相似的内容,从而提供个性化的推荐。在图像检索中,DataVec可以通过图像特征向量,快速找到与查询图像相似的图片。在自然语言处理(NLP)中,DataVec可以通过文本嵌入,快速找到与查询文本语义相似的文档。

3.2 架构设计

3.2.1 SQL层
  • Embedding:支持与DeepSeek、Qwen、盘古大模型对接,将高维数据转化为向量。
  • 混合查询:基于RBO生成标量和向量混合的查询,支持大规模标签的过滤查询能力以及基于过滤率的向量查询策略。
  • 向量计算:通过鲲鹏SVE/SME指令优化的距离计算如欧氏距离、余弦距离等。
3.2.2 存储引擎层
  • 向量存储:支持单页最高64000维向量数据存储
  • 向量索引:支持多种高效ANN索引。
3.2.3 硬件加速层

基于鲲鹏Boostkit量化压缩、向量指令集等软硬结合技术加速检索。

BoostKit加速:openGauss DataVec 深度结合鲲鹏硬件,通过量化压缩算法、Rerank精排、向量化指令加速等软硬协同技术,加速向量检索进程。

d129e6dfa6c500e97b82520c5fd481a7.png

3.2.4 PQ量化压缩

乘积量化(Product Quantization, PQ)是一种基于高效压缩高维向量的方法,适用于大规模数据集的相似度搜索。通过将高维向量分割成为多个低维子向量,并对每个子向量进行独立聚类,将原始向量表示为一系列质心,从而显著减少内存使用和提升检索速度。

3.2.5 PQ码本训练

训练阶段:将向量空间按照维度划分成若干子空间,然后再每个子空间采用聚类方法得到N个中心点,最后分段底库向量和分段query向量与分段聚类中心点进行距离求解,进而获得底库索引表和query距离表。流程如下

  • step1:原始特征向量进行数据切分,切分后维度为N × M,其中N维底库元素的数量,M维切分的段数。
  • step2:对切分数据进行K-Means据类,一般选择28 = 256个聚类中心,聚类后的训练码维度维K × M,K维聚类中心的个数。
  • step3:底库切分向量和训练码本进行IP或者L2距离求解获得距离值,选择距离值中最小的据类中心索引,进而生成底库向量编码表,其维度为N × M。
  • step4:对query向量进行切分,执行与step3相同的操作,生成query向量距离表,其维度为K × M。

f2fef705c26be4351f3dc55c0bc5d0ed.png

3.2.6 PQ检索

检索阶段:通过训练阶段生成的底库索引表和query距离表,进行查表进而获得query向量与底库向量之间的距离。仅需通过M次查表和M次相加,即可得到query向量和任一底库向量之间的距离。

3b70b43851cecb03d510296cbecd6f3c.png

3.2.7 分层导航+PQ融合索引

将PQ的查表法和分层导航索引结合在一起,用查表法来代替向量距离计算,进而提高检索性能,在索引构时,并行构建分层导航图和PQ索引。在检索阶段,对0层以上的图求解query向量和图中节点之间的距离时采用Flat求解器求解,这样可以保证为第0层提供较好的入口节点。同时,顶层节点数较小也不会花费较长时间。在第0层进行检索时,采用PQ求解器的码本来代替距离求解,极大提高了计算效率。

为了进一步提高检索精度,对采用PQ查表法获取的候选集,进行二级精排,通过Flat求解器更新候选集中元素的距离,此时更新的距离为候选集向量与query向量之间的真是距离。然后对更新距离后的候选集进行二次更新,输出最终TopK结果。

3.2.8 向量指令集加速

具体来说,鲲鹏指令集包括一系列优化的指令,如NEON指令和内联汇编,这些指令能够加速向量运算、数据预取和流水线处理。通过利用鲲鹏处理器的硬件加速特性和优化的指令集,ANN算法能够在处理大规模数据集时显著提高性能和效率。

3.2.9 标题向量混合查询

DataVec还能够同时处理标量数据(如数值、类别)和向量数据(如文本、音视频)。这种混合查询的支持使得用户可以在同一个查询中结合不同类型的数据,从而实现更复杂和精细的分析。

0099ef00cd05507d2cd50f5a4a35dcc8.png

  • SQL Join :支持相似性搜索JOIN关系型数据。
  • 复杂、融合SQL:
  • 支持所有类型的工作负载和数据模型:Graph, Text, JSON, Spatial, Relational, etc。
  • 支持所有SQL,包括复杂的运算和功能:Window analytic functions, stored procedures, aggregation。
  • 与向量搜索组合成复杂融合的SQL:
    • 初始按照标量过滤条件生成过滤位图信息,通过ANN检索算法获取向量数据,将同时满足位图过滤和向量检索的数据返回,否则增大候选集再次检索。
3.2.10 支持原地更新引擎

ANN索引页面中在每个Element Tuple尾部附加xmin和xmax字段,从而支持原地更新引擎。这些字段在索引构建和查询过程中起到关键作用,确保数据的可见性和一致性。在实际实现中,插入新数据时系统会记录当前事务ID到xmin字段;在删除数据时系统会更新xmax字段。原地更新引擎采用原位更新的方式极大的节约了空间,将回滚段、数据页面分离存储,具备高效、平稳的IO能力。

38c6e6760485e3a7ec098b9770d7df27.png

3.2.11 并行构建索引

ANN支持并行构建索引,通过将数据集分成若干个子集分配到不同工作线程上,在每个线程上独立计算并将各线程结果合并形成最终全局索引,这极大地提升了处理大规模数据集的效率。

  • 数据分片:数据按照工作线程数划分,切分为若干子集。
  • 并行处理:leader线程创建Bgworker,每个Bgworker并行扫描各个数据子集,计算向量之间距离加入候选集。
  • 结果合并:leader线程合并所有线程结果并进行排序,然后持久化到页面上。

3b5e99c79e0aea8619dbe0389f198b56.png

3.3 openGauss DataVec + Dify搭建智能助手平台

在当今数字化和智能化的时代,大语言模型(LLM)的应用正以前所未有的速度改变着各个领域的工作方式和用户体验。Dify 作为一个开源的大语言模型应用开发平台,为开发者们提供了便捷且强大的工具,助力构建从基础智能体到复杂人工智能工作流程的各类大语言模型应用。其核心优势在于集成了检索增强(RAG)引擎,通过对海量数据的智能检索与分析,能够精准地为大语言模型提供相关信息,极大地提升模型输出的准确性和相关性。 本文着重介绍如何部署Dify,并使用openGauss DataVec向量数据库作为RAG引擎语料库,从而搭建出高效智能的助手平台。

Dify部署

Dify源码地址:https://github.com/langgenius/dify/archive/refs/tags/1.1.3.tar.gz

配置参数

在获取源码压缩包后,需要创建特定目录并解压源码。具体操作如下:

sudo mkdir /usr/local/dify
sudo chown developer:developer /usr/local/dify/
cd /usr/local/dify/ 
git clone https://gitee.com/dify_ai/dify.git

接下来的关键步骤是配置环境变量。在此过程中,需要修改.env文件,将VECTOR_STORE设置为opengauss。执行以下命令进行文件复制和编辑:

cp .env.example .env
vim .env

8a8cd3011e4a59bdbe648853dcc825ef.png

完成上述配置后,执行以下命令,系统将自动拉取对应的Docker镜像,并启动Dify服务。

docker-compose up -d

如果Dify拉取对应的镜像失败,请查阅Dify在Linux本地部署方法。

容器启动完毕后,为了确保各项服务均正常运行,可以执行docker ps命令。若一切顺利,会有类似下图所示的运行状态。

7c61755b233e237cee207e38ff35cd18.png

后面则是Dify的功能应用,此案例主要是Difty用opengauss存储向量数据示例。Dify的AI集成服务不属于本案例的重点内容,故读者可以自行上网查阅Dify相关运用文档与资料。

DataVec向量数据库引擎具体示例见OpenGauss官方文档:

https://docs.opengauss.org/zh/docs/latest/docs/DataVec/openGauss-Dify.html

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值