openGauss 列存表PSort索引
openGauss 列存表 PSort 索引
概述
PSort(Partial sort) Index 是在列存表的列上建的聚簇索引。CUDesc 上有每个 CU 的 min 和 max 值,但如果业务的数据模型较为离散,查询时通过 min 和 max 值去过滤 CU 会出现大量的 CU 误读取,例如每个 CU 的 min 和 max 跨度都比较大时,其查询效率接近全表扫描。例如下图中的场景,查询 2 基本命中所有的 CU, 此时查找近似全表扫描。
PSort 索引可以对部分区间(一般会包含多个 CU 覆盖的行)内的数据按照索引键进行排序,使得 CU 之间的交集尽量减少,提升查询的效率。
PSort 索引使用
在批量插入列存表的过程中,如果发现有 PSort 索引,会先对这批数据进行排序。PSort 索引表的组织形式也是 cstore 表(CUDesc 是 astore 表),表的字段包含了索引键的各个字段,加上对应的行号(TID)字段。插入数据的过程中如果发现有 PSort 索引,会将一定数量的数据按照 PSort 索引的索引键进行排序,与 TID 字段共同拼装成向量数组,再插入到 PSort 索引的 cstore 表中。 所以 PSort 索引数据中列数比实际的索引键要多一列,多出的这一列用于存储这条记录在数据 cstore 存储中的位置。
// 构建 PSort 索引过程中构造索引数据
inline void ProjectToIndexVector(VectorBatch *scanBatch, VectorBatch *outBatch, IndexInfo *indexInfo)
{
Assert(scanBatch && outBatch && indexInfo);
int numAttrs = indexInfo->ii_NumIndexAttrs;
AttrNumber *attrNumbers = indexInfo->ii_KeyAttrNumbers;
Assert(outBatch->m_cols == (numAttrs + 1));
// index column
for (int i = 0; i < numAttrs; i++) {
AttrNumber attno = attrNumbers[i];
Assert(attno > 0 && attno <= scanBatch->m_cols);
// shallow copy
outBatch->m_arr[i].copy(&scanBatch->m_arr[attno - 1]);
}
// ctid column
// 最后一列是 tid
outBatch->m_arr[numAttrs].copy(scanBatch->GetSysVector(-1));
outBatch->m_rows = scanBatch->m_rows;
}
cstore 表执行插入流程,如果有 Psort 索引,会先将数据插入排序队列
void CStoreInsert::BatchInsert(in VectorBatch* pBatch, in int options)
{
Assert(pBatch || IsEnd());
/* keep memory space from leaking during bulk-insert */
MemoryContext oldCnxt = MemoryContextSwitchTo(m_tmpMemCnxt);
// Step 1: relation has partial cluster key
// We need put data into sorter contatiner, and then do
// batchinsert data
if (NeedPartialSort()) {
Assert(m_tmpBatchRows);
if (pBatch) {
Assert(pBatch->m_cols == m_relation->rd_att->natts);
m_sorter->PutVecBatch(m_relation, pBatch); // 插入局部排序队列
}
if (m_sorter->IsFull() || IsEnd()) { // 排序队列满了或者插入数据输入结束
m_sorter->RunSort(); // 按照索引键排序
/* reset and fetch next batch of values */
DoBatchInsert(options);
m_sorter->Reset(IsEnd());
/* reset and free all memory blocks */
m_tmpBatchRows->reset(false);
}
}
// Step 2: relation doesn't have partial cluster key
// We need cache data until batchrows is full
else {
Assert(m_bufferedBatchRows);
// If batch row is full, we can do batchinsert now
if (IsEnd()) {
if (ENABLE_DELTA(m_bufferedBatchRows)) {
InsertDeltaTable(m_bufferedBatchRows, options);
} else {
BatchInsertCommon(m_bufferedBatchRows, options);
}
m_bufferedBatchRows->reset(true);
}
// we need cache data until batchrows is full
if (pBatch) {
Assert(pBatch->m_rows <= BatchMaxSize);
Assert(pBatch->m_cols && m_relation->rd_att->natts);
Assert(m_bufferedBatchRows->m_rows_maxnum > 0);
Assert(m_bufferedBatchRows->m_rows_maxnum % BatchMaxSize == 0);
int startIdx = 0;
while (m_bufferedBatchRows->append_one_vector(
RelationGetDescr(m_relation), pBatch, &startIdx, m_cstorInsertMem)) {
BatchInsertCommon(m_bufferedBatchRows, options);
m_bufferedBatchRows->reset(true);
}
Assert(startIdx == pBatch->m_rows);
}
}
// Step 3: We must update index data for this batch data
// if end of batchInsert
FlushIndexDataIfNeed();
MemoryContextReset(m_tmpMemCnxt);
(void)MemoryContextSwitchTo(oldCnxt);
}
图 cstore 表插入流程示意图
插入流程中更新索引数据的代码
void CStoreInsert::InsertIdxTableIfNeed(bulkload_rows* batchRowPtr, uint32 cuId)
{
Assert(batchRowPtr);
if (relation_has_indexes(m_resultRelInfo)) {
/* form all tids */
bulkload_indexbatch_set_tids(m_idxBatchRow, cuId, batchRowPtr->m_rows_curnum);
for (int indice = 0; indice < m_resultRelInfo->ri_NumIndices; ++indice) {
/* form index-keys data for index relation */
for (int key = 0; key < m_idxKeyNum[indice]; ++key) {
bulkload_indexbatch_copy(m_idxBatchRow, key, batchRowPtr, m_idxKeyAttr[indice][key]);
}
/* form tid-keys data for index relation */
bulkload_indexbatch_copy_tids(m_idxBatchRow, m_idxKeyNum[indice]);
/* update the actual number of used attributes */
m_idxBatchRow->m_attr_num = m_idxKeyNum[indice] + 1;
if (m_idxInsert[indice] != NULL) {
/* 插入PSort 索引 */
m_idxInsert[indice]->BatchInsert(m_idxBatchRow, 0);
} else {
/* 插入 cbtree/cgin 索引 */
CStoreInsert::InsertNotPsortIdx(indice);
}
}
}
}
索引插入流程和普通 cstore 数据插入相同。
使用 PSort 索引查询时,由于 PSort 索引 CU 内部已经有序,因此可以使用二分查找快速找到对应数据在 psort 索引中的行号,这一行数据的 tid 字段就是这条数据在数据 cstore 中的行号。
图-2 PSort 索引查询示意图
openGauss 列存表PSort索引的更多相关文章
- Greenplum 行存、列存,堆表、AO表的原理和选择
转载自: https://github.com/digoal/blog/blob/master/201708/20170818_02.md?spm=a2c4e.11153940.blogcont179 ...
- Greenplum列存压缩表索引机制
列存压缩表,简称AOCS表 数据生成 create table testao(date text, time text, open float, high float, low float, volu ...
- mysql 查询指定数据库所有表, 指定表所有列, 指定列所有表 所有外键及索引, 以及索引的创建和删除
查询指定 数据库 中所有 表 (指定数据库的,所有表) // 可以把 TABLE_NAME 换成 * 号, 查看更丰富的信息 SELECT TABLE_NAME FROM information_sc ...
- 【SQL进阶】【表默认值、自增、修改表列名、列顺序】Day02:表与索引操作
一.表的创建.修改与删除 1.创建一张新表 [设置日期默认值.设置id自增] [注意有备注添加备注COMMENT] CREATE TABLE user_info_vip( id int(11) pri ...
- mysql优化 | 存储引擎,建表,索引,sql的优化建议
个人对于选择存储引擎,建表,建索引,sql优化的一些总结,给读者提供一些参考意见 推荐访问我的个人网站,排版更好看: https://chenmingyu.top/mysql-optimize/ 存储 ...
- Oracle 学习总结 - 表和索引的性能优化
表的性能 表的性能取决于创建表之前所应用的数据库特性,数据库->表空间->表,创建数据库时确保为每个用户创建一个默认的永久表空间和临时表空间并使用本地管理,创建表空间设为本地管理并且自动段 ...
- ORACLE表、索引和分区详解
ORACLE表.索引和分区 一.数据库表 每种类型的表都有不同的特性,分别应用与不同的领域 堆组织表 聚簇表(共三种) 索引组织表 嵌套表 临时表 外部表和对象表 1.行迁移 建表过程中可以指定以下两 ...
- Oracle索引梳理系列(五)- Oracle索引种类之表簇索引(cluster index)
版权声明:本文发布于http://www.cnblogs.com/yumiko/,版权由Yumiko_sunny所有,欢迎转载.转载时,请在文章明显位置注明原文链接.若在未经作者同意的情况下,将本文内 ...
- SOME:收缩数据库日志文件,查看表数据量和空间占用,查看表结构索引修改时间
---收缩数据库日志文件 USE [master]ALTER DATABASE yourdatabasename SET RECOVERY SIMPLE WITH NO_WAITALTER DATAB ...
- [BILL WEI]SQL 如何将查询到的列作为表名去查询数据
我们在做sql查询的时候,有时候需要将查询的列作为表名,去引用,然后再次查询 declare @table_name varchar(20) select @table_name=table_name ...
随机推荐
- 2024年,提升Windows开发和使用体验实践 - 小工具篇
前言 本来是一篇文章的,不知不觉写成了系列. 其实开工那几天就已经写好了长文,这几天一忙就没连着发了. 本文介绍一些 Windows 上用的小工具. 美化/折腾/小工具 虽然这是在用 Windows ...
- Nebula Graph 源码解读系列 | Vol.02 详解 Validator
整体架构 Nebula Graph Query Engine 主要分为四个模块,分别是 Parser.Validator.Optimizer 和 Executor. Parser 完成对语句的词法语法 ...
- C++ 错误 具有类型“const sort”的表达式会丢失一些 const-volatile 限定符以调用“bool sort::operator ()(int,int)” 如下:环境 vs2019 内容:set内置函数排序
C++ 错误 具有类型"const sort"的表达式会丢失一些 const-volatile 限定符以调用"bool sort::operator ()(int,int ...
- redis---面经
redis 偏应用的总结:redis 应用 Redis是什么? Redis是什么 对象 字符串 自增,键值对. SDS数据结构记录长度,已经使用,和总共长度,并且提前多余出容量,防止一直扩容缩容. 字 ...
- Rtsp转Flv在浏览器中播放
目录 概述 环境 项目目录清单 项目搭建步骤 引入相关npm依赖 实例化一个express应用 创建WebsocketServer并解析rtsp 使用flv播放 浏览器中测试 代码 引用 概述 众所周 ...
- ThinkPHP 3.2.3
说明手册 https://www.kancloud.cn/manual/thinkphp/1706 下载地址 https://gitee.com/liu21st/thinkphp32 thinkPHP ...
- 聚焦“云XR如何赋能元宇宙”,3DCAT实时云渲染首届行业生态合作交流会成功举办
2021年12月17日下午,由深圳市瑞云科技有限公司主办,深圳市虚拟现实产业联合会协办的云XR如何赋能元宇宙--3DCAT实时云渲染首届行业生态合作交流会圆满落幕.此次活动围绕 "云XR如何 ...
- APT案例之点击事件
目录介绍 01.创建项目步骤 1.1 项目搭建 1.2 项目功能 02.自定义注解 03.创建Processor 04.compiler配置文件 05.编译jar 06.如何使用 07.编译生成代码 ...
- 三维模型OBJ格式轻量化的数据压缩与性能平衡分析
三维模型OBJ格式轻量化的数据压缩与性能平衡分析 三维模型的OBJ格式轻量化数据压缩在保持性能的同时,可以减小文件大小.提高加载速度和节省存储空间.然而,在进行数据压缩时,需要权衡压缩比率和模型质量之 ...
- Liunx-LVM创建与扩容
LVM是 Logical Volume Manager(逻辑卷管理)的简写,它是Linux环境下对磁盘分区进行管理的一种机制,它由Heinz Mauelshagen在Linux 2.4内核上实现,最新 ...