Clickhouse的联合索引

Clickhouse 有了单独的键索引,为什么还需要有联合索引呢?了解过mysql的兄弟们应该都知道这个事。
对sql比较熟悉的兄弟们估计看见这个联合索引心里大概有点数了,不过clickhouse的联合索引相比mysql的又有些不一样了,mysql 很遵循最左匹配原则,但是clickhouse 又似乎有些不一样,具体哪里不一样呢,那么我们还是和上一篇 Q220240407–clickhouse 中的索引大白话一样,通过引用这张表hits_UserID_URL 来揭开下这个谜底。

一:联合索引
回到hits_UserID_URL的建表语句如下,我们当时创建表的时候,我们的主键就指定了UserID 和URL 如下:

CREATE TABLE hits_UserID_URL
(
UserID UInt32,
URL String,
EventTime DateTime
)
ENGINE = MergeTree
PRIMARY KEY (UserID, URL)
ORDER BY (UserID, URL, EventTime);
这样的主键大于1的情况,生成的那个primary.idx 索引文件(参考上一篇) 也就是会每一行都会生成n列记录(n>1),这样的索引文件我们就可以称之为联合索引文件是吧,故而UserID 和URL就形成了一个联合索引。其实为什么需要联合索引呢?那肯定是说在实际业务中这两个列经常放在一起查询,所以才会考虑给这两个列加索引。

但是联合索引的效果就真的好吗,这个取决于第一列索引的基数,什么是基数呢?说白了,就是某个列的值去重之后的个数,如果个数多说明基数高,如果个数少就说明基数低;那为什么联合索引的效果是取决于基数呢?因为联合索引在找数据的时候是使用排除搜索法的,下面我们来讲讲排除搜索法

1.1: 排除搜索法

排除搜索法顾名思义就是排除掉一些数据,然后搜索一波:

因为userId 和url 是按照字典顺序升序排列的,假如左边的键userID 的基数比较低,那么相同的userId可能会分布在很多的grandule 里面,也就可能分布在索引标记上,如下所示:

在这里插入图片描述

所以假如我们查询url <=w3 的数据,那么我们就可以看看相邻的两个grandule的最后一个url的值和第一个url的值;如果第一个url的值是w3, 第二个url 的值是w4,那么我们需要搜索的grandule 就只有前面的第一个grandule 和 之前的grandule 里面了,如法炮制,对着前面的所有的grandule,使用二分法,就可以在小于等于 o(logn)的时间复杂度找到对应的grandule;而且需要加载的grandule 非常少,这个效率挺高

但是,哈哈哈,凡事都怕但是,在实际生产环境中,userID和url的基数可能都很高,那么相同的userID 值可能就不会分布在多个表行和grandule 中,所以索引文件中的url 值就不太可能单调递增,如下所示:在这里插入图片描述

这个时候使用排除搜索法估计就要全表扫描了,使用不了二分法了;这个查询效率就贼低了,所以如果我们需要提高查找效率,就要使用多个主键索引了,而不是单纯的用联合索引。

二: 使用多个主键索引

2.1: 创建另一张表

最常见的方法就是我们再建另一张表,这张表的主键索引我们设置为url,如下所示:

CREATE TABLE hits_URL_UserID
(
UserID UInt32,
URL String,
EventTime DateTime
)
ENGINE = MergeTree
PRIMARY KEY (URL, UserID)
ORDER BY (URL, UserID, EventTime)
SETTINGS index_granularity = 8192, index_granularity_bytes = 0;

INSERT INTO hits_URL_UserID
SELECT * from hits_UserID_URL;

OPTIMIZE TABLE hits_URL_UserID FINAL;
这个当然可以加快查询,但是如果我们的系统已经上线了的话,这个改动还要应用系统那边改,不太实用

2.2: 使用物化视图

我们可以使用物化视图,不改动原表的情况下,如下所示:

CREATE MATERIALIZED VIEW mv_hits_URL_UserID
ENGINE = MergeTree()
PRIMARY KEY (URL, UserID)
ORDER BY (URL, UserID, EventTime)
POPULATE
AS SELECT * FROM hits_UserID_URL;

使用populate 的关键字是让原表的所有值钱的数据都导入这个物化视图,后续有的数据也会同步到这个物化视图;

但是这个的麻烦点也和刚刚的第一种方法一样,需要应用系统改动适配查询物化视图表,但是物化视图在做聚合方面很有用,如下所示:

–agg+物化视图本地表
–drop table if exists glab.bi_dws_lbs_adapter_agg_mv_local on cluster glab_cluster;

create materialized view glab.bi_dws_lbs_adapter_agg_mv_local on cluster glab_cluster(
id String,
idType AggregateFunction(argMax, String, UInt64 ),
geohash AggregateFunction(argMax, String, UInt64 ),
locType AggregateFunction(argMax, Int64, UInt64 ),
wifimac AggregateFunction(argMax, String, UInt64 ),
ip AggregateFunction(argMax, String, UInt64 ),
baseStation AggregateFunction(argMax, String, UInt64 ),
connectType AggregateFunction(argMax, Int64, UInt64 ),
equipmentId AggregateFunction(argMax, String, UInt64 ),
time AggregateFunction(max, UInt64 )
)
engine = AggregatingMergeTree()
partition by tuple()
order by id
as
select
id,
argMaxState ( id_type, ts ) AS idType,
argMaxState ( geohash12, ts ) AS geohash,
argMaxState ( loc_type, ts ) AS locType,
argMaxState ( wifimac, ts ) AS wifimac,
argMaxState ( ip, ts ) AS ip,
argMaxState ( base_station, ts ) AS baseStation,
argMaxState ( connect_type, ts ) AS connectType,
argMaxState ( equipment_id, ts ) AS equipmentId,
maxState( ts ) AS time
from glab.bi_dws_lbs_adapter_local
where geohash12 != ‘’ AND geohash12 IS NOT NULL
group by id;

–agg+物化视图集群表
CREATE TABLE glab.bi_dws_lbs_adapter_agg_mv on cluster glab_cluster as bi_dws_lbs_adapter_agg_mv_local
ENGINE = Distributed(‘glab_cluster’, ‘glab’, ‘bi_dws_lbs_adapter_agg_mv_local’, murmurHash3_32(id))

参考链接:https://cf.cloudglab.cn/pages/viewpage.action?pageId=226211113

2.3: 使用投影projection

上述两个方法都是需要应用系统适配,但是这个projection 就很好的解决了这个问题,BI这边改动就行,不需要应用改动,如下所示:

ALTER TABLE hits_UserID_URL
ADD PROJECTION prj_url_userid
(
SELECT *
ORDER BY (URL, UserID)
);

ALTER TABLE hits_UserID_URL
MATERIALIZE PROJECTION prj_url_userid; (使用materalize 是为了让原始的数据形成另一个索引)

所以当系统查询慢的情况下,如果就是因为联合索引的问题,我们可以使用projection,成本最小;如果需要查询诸如max(ts) 的geohash ,那就要用到物化视图了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/787340.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Springboot各个版本维护时间

Springboot各个版本维护时间

【 正己化人】 把自己做好,能解决所有问题

阳明先生说&#xff1a;与朋友一起辩论学问&#xff0c;纵然有人言辞观点浅近粗疏&#xff0c;或者是炫耀才华、显扬自己&#xff0c;也都不过是毛病发作。只要去对症下药就好&#xff0c;千万不能怀有轻视别人的心理&#xff0c;因为那不是君子与人为善的心。 人会爱发脾气、…

微信服务里底部的不常用功能如何优化的数据分析思路

图片.png 昨天下午茶时光&#xff0c;和闺蜜偶然聊起&#xff0c;其实在微信服务底部&#xff0c;有很多被我们忽略遗忘&#xff0c;很少点过用过的功能服务&#xff0c;往往进入服务只为了收付款或进入钱包&#xff0c;用完就走了&#xff0c;很少拉到底部&#xff0c;看到和用…

Python函数 之 函数基础

print() 在控制台输出 input() 获取控制台输⼊的内容 type() 获取变量的数据类型 len() 获取容器的⻓度 (元素的个数) range() ⽣成⼀个序列[0, n) 以上都是我们学过的函数&#xff0c;函数可以实现⼀个特定的功能。我们将学习⾃⼰如何定义函数, 实现特定的功能。 1.函数是什么…

LiveNVR监控流媒体Onvif/RTSP用户手册-录像计划:批量配置、单个配置、录像保存(天)、配置时间段录像

TOC 1、录像计划 支持单个通道 或是 通道范围内配置支持快速滑选支持录像时间段配置 1.1、录像存储位置如何配置&#xff1f; 2、RTSP/HLS/FLV/RTMP拉流Onvif流媒体服务 支持 Windows Linux 及其它CPU架构&#xff08;国产、嵌入式…&#xff09;操作系统安装包下载 、 安装…

亚马逊跟卖采集选品,2小时自动检索3000条商品数据与...

自动查商标局2个小时2928条数据。 ERP采集3000条数据需要多久&#xff1f;10&#xff1a;34开始的&#xff0c;12&#xff1a;52分&#xff0c;应该是两个小时多。采集3000条数据&#xff0c;2928条&#xff0c;平均每个就是3秒左右。 可以看一下采集出来的数据&#xff0c;打…

【C++知识点总结全系列 (08)】:面向对象编程OOP

这里写目录标题 1、OOP概述(1)面向对象四大特征A.抽象B.封装C.继承D.多态 (2)构造函数A.What&#xff08;什么是构造函数&#xff09;B.Why&#xff08;构造函数的作用&#xff09;C. Which&#xff08;有哪些构造函数&#xff09; (3)析构函数A.What&#xff08;什么是析构函数…

Python基础知识——(003)

文章目录 P12——11. 保留字和标识符 1. 保留字 2. Python标识符的命名规则&#xff08;必须遵守&#xff09; 3. Python标识符的命名规范&#xff08;建议遵守&#xff09; P13——12. 变量与常量 变量的语法结构 变量命名应遵循以下几条规则 常量 P14——13. 数值类型…

数据结构作业/2024/7/9

2>实现双向循环链表的创建、判空、尾插、遍历、尾删、销毁 fun.c #include "head.h" //1.双向循环链表的创建 doubleloop_ptr create_list() …

如何在 PostgreSQL 中确保数据的异地备份安全性?

文章目录 一、备份策略1. 全量备份与增量备份相结合2. 定义合理的备份周期3. 选择合适的备份时间 二、加密备份数据1. 使用 PostgreSQL 的内置加密功能2. 使用第三方加密工具 三、安全的传输方式1. SSH 隧道2. SFTP3. VPN 连接 四、异地存储的安全性1. 云存储服务2. 内部存储设…

Spring Cloud 引入

1.单体架构&#xff1a; 定义&#xff1a;所有的功能实现都打包成一个项目 带来的后果&#xff1a; ①后端服务器的压力越来越大&#xff0c;负载越来越高&#xff0c;甚至出现无法访问的情况 ②业务越来越复杂&#xff0c;为了满足用户的需求&#xff0c;单体应用也会越来越…

C#Modbus通信

目录 1&#xff0c;辅助工具。 2&#xff0c;初识Modbus。 3&#xff0c;基于ModbusRTU的通信。 3.1&#xff0c;RTU与ASCII模式区别 3.2&#xff0c;Modbus存储区 3.3&#xff0c;报文格式 3.4&#xff0c;异常代码 3.5&#xff0c;详细文档连接 。 3.6&#xff0c;代…

数据结构——顺序表【C】

顺序表 1. 顺序表的概念以及结构1.1概念1.2静态顺序表和动态顺序表 2. 顺序表接口模拟实现接口总览2.1 初始化数据和销毁容器 2.2 顺序表的尾插和尾删2.3 头插和头删2.4 任意位置插入和删除数据2.5 查找数据 3. 顺序表的问题 &#xff1a; 1. 顺序表的概念以及结构 1.1概念 顺…

生成多个ssh访问不同git

如果&#xff0c;你的git代码仓库&#xff0c;比如说腾讯云coding&#xff0c;通过ssh秘钥访问&#xff0c;一直用的好好的&#xff0c;有一天&#xff0c;你又增加一个aliyun云效的代码仓库&#xff0c;又配置了aliyun云效的秘钥并且&#xff0c;根据aliyun云效的官方文档上传…

DOM(文档对象模型)生命周期事件

前言 DOM 生命周期事件涉及到从创建、更新到销毁 DOM 元素的不同阶段。 ● 我们来看下当HTML文档加载完再执行JavaScript代码 document.addEventListener(DOMContentLoaded, function (e) {console.log(HTML parsed adn DOM tree built!, e); })● 除此之外&#xff0c;浏览…

Elasticsearch详细介绍

B站对应视频&#xff1a; Elasticsearch01-01.为什么学习elasticsearch_哔哩哔哩_bilibili 大多数日常项目&#xff0c;搜索肯定是访问频率最高的页面之一。目前搜索功能是基于数据库的模糊搜索来实现的&#xff0c;存在很多问题。 首先&#xff0c;查询效率较低。 由于数据…

【work】AI八股-神经网络相关

Deep-Learning-Interview-Book/docs/深度学习.md at master amusi/Deep-Learning-Interview-Book GitHub 网上相关总结&#xff1a; 小菜鸡写一写基础深度学习的问题&#xff08;复制大佬的&#xff0c;自己复习用&#xff09; - 知乎 (zhihu.com) CV面试问题准备持续更新贴 …

如何在 SwiftUI 中开发定制 MapKit 功能

文章目录 介绍地图样式imagery-map 地图交互地图控件总结 介绍 在上一篇文章中&#xff0c;我们探讨了 SwiftUI 中新的 MapKit API 的基础知识。现在&#xff0c;让我们深入 MapKit API 的定制点&#xff0c;以便根据我们的需求定制地图呈现。 地图样式 新的 MapKit API 引入…

藏汉翻译通作为翻译软件的优势有哪些?

藏汉翻译通作为一款专业的藏汉双语翻译软件&#xff0c;具有以下优势&#xff1a; 人工智能技术应用&#xff1a;藏汉翻译通利用了人工智能翻译和语音识别合成技术&#xff0c;提供智能藏文翻译服务。 高准确率&#xff1a;文字识别准确率可达90%&#xff0c;语音识别转化文字…

pytest-yaml-sanmu(六):YAML数据驱动测试

如果说 pytest 中哪些标记使用得最多&#xff0c;那无疑是 parametrize 了&#xff0c; 它为用例实现了参数化测试的能力&#xff0c;进而实现了数据驱动测试的能力。 1. 使用标记 parametrize 的使用需要提高两个内容&#xff1a; 参数名 参数值 pytest 在执行用例时&…