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 ,那就要用到物化视图了。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring源码二十:Bean实例化流程三

上一篇Spring源码十九&#xff1a;Bean实例化流程二中&#xff0c;我们主要讨论了单例Bean创建对象的主要方法getSingleton了解到了他的核心流程无非是&#xff1a;通过一个简单工厂的getObject方法来实例化bean&#xff0c;当然spring在实例化前后提供了扩展如&#xff1a;bef…

第5章-组合序列类型

#全部是重点知识&#xff0c;必须会。 了解序列和索引|的相关概念 掌握序列的相关操作 掌握列表的相关操作 掌握元组的相关操作 掌握字典的相关操作 掌握集合的相关操作1&#xff0c;序列和索引 1&#xff0c;序列是一个用于存储多个值的连续空间&#xff0c;每一个值都对应一…

灵活多变的对象创建——工厂方法模式(Python实现)

1. 引言 大家好&#xff0c;又见面了&#xff01;在上一篇文章中&#xff0c;我们聊了聊简单工厂模式&#xff0c;今天&#xff0c;我们要进一步探讨一种更加灵活的工厂设计模式——工厂方法模式。如果说简单工厂模式是“万能钥匙”&#xff0c;那工厂方法模式就是“变形金刚”…

Python采集京东标题,店铺,销量,价格,SKU,评论,图片

京东的许多数据是通过 JavaScript 动态加载的&#xff0c;包括销量、价格、评论和评论时间等信息。我们无法仅通过传统的静态网页爬取方法获取到这些数据。需要使用到如 Selenium 或 Pyppeteer 等能够模拟浏览器行为的工具。 另外&#xff0c;京东的评论系统是独立的一个系统&a…

offer题目33:判断是否是二叉搜索树的后序遍历序列

题目描述&#xff1a;输入一个整数数组&#xff0c;判断该数组是不是某二叉搜索树的后序遍历结果。如果是则返回true,否则返回false。假设输入的数组的任意两个数字都互不相同。例如&#xff0c;输入数组{5,7,6,9,11,10,8},则返回true,&#xff0c;因为这个整数是下图二叉搜索树…

c++内存管理(上)

目录 引入 分析 说明 C语言中动态内存管理方式 C内存管理方式 new/delete操作内置类型 new和delete操作自定义类型 引入 我们先来看下面的一段代码和相关问题 int globalVar 1; static int staticGlobalVar 1; void Test() { static int staticVar 1; int localVar 1…

数图助推朝阳佳惠辽宁华联开启数字化导航、精细化管理新纪元!

近期&#xff0c;辽宁省著名零售企业朝阳佳惠与辽宁华联&#xff0c;秉持创新精神&#xff0c;大胆尝试&#xff0c;在品类空间管理方面推出了创新举措。引入了先进的数图可视化陈列管理系统&#xff0c;通过智能化、直观化的方式优化商品布局。此举不仅大幅提高了商品管理的效…

element-ui封装分页组件:实现首页、上一页、下一页、末页、跳转按钮

首页、上一页、下一页、末页、跳转按钮 因为el-pagination只有一个插槽&#xff0c;所以通过两个el-pagination插槽分别加入首页、末页按钮&#xff0c;再拼接这两个el-pagination的方式来实现首页、末页按钮跳转按钮不用加事件&#xff0c;如果el-pagination修改了前往的页数…

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

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

聚类分析方法(二)

目录 三、层次聚类方法&#xff08;一&#xff09;层次聚类策略&#xff08;二&#xff09;AGNES算法&#xff08;三&#xff09;DIANA算法 四、密度聚类方法&#xff08;一&#xff09;基本概念&#xff08;二&#xff09;算法描述&#xff08;三&#xff09;计算实例&#xf…

Google账号输入用户名和密码后提醒要到手机通知点是,还要点击数字,但是我手机收不到

有一些朋友换了一个新的电脑后手机登录谷歌账号时&#xff0c;用户名和密码都正确输入以后&#xff0c;第三步弹出一个提示&#xff0c;要在手机上的通知栏点击是&#xff0c;并且点击手机上相应的数字才能继续登录。 但是自己的手机上下拉通知栏却没有来自谷歌的通知&#xf…

符号同步、定时同步和载波同步

符号同步、定时同步和载波同步是通信系统中重要的同步技术&#xff0c;它们各自承担着不同的功能和作用。以下是对这三种同步技术的详细解释&#xff1a; 符号同步 定义&#xff1a; 符号同步&#xff0c;也称为定时恢复或时钟恢复&#xff0c;是指在数字通信系统中&#xff…

继承关系中的访问控制

继承关系中的访问控制 类中成员的访问权限类继承中的访问权限派生类向基类转换的权限问题&#xff08;向上转型&#xff09;友元在继承中的访问权限 类中成员的访问权限 public&#xff1a;类的对象&#xff08;外部&#xff09;可以访问&#xff0c;派生类也可以访问protecte…

LeNet原理及代码实现

目录 1.原理及介绍 2.代码实现 2.1model.py 2.2model_train.py 2.3model.test.py 1.原理及介绍 2.代码实现 2.1model.py import torch from torch import nn from torchsummary import summaryclass LeNet(nn.Module):def __init__(self):super(LeNet, self).__init__…

nuxt、vue树形图d3.js

直接上代码 //安装 npm i d3 --save<template><div class"d3"><div :id"id" class"d3-content"></div></div> </template> <script> import * as d3 from "d3";export default {props: {d…

Github Actions 构建Vue3 + Vite项目

本篇文章以自己创建的项目为例&#xff0c;用Github Actions构建。 Github地址&#xff1a;https://github.com/ling08140814/myCarousel 访问地址&#xff1a;https://ling08140814.github.io/myCarousel/ 具体步骤&#xff1a; 1、创建一个Vue3的项目&#xff0c;并完成代…

接口基础知识1:认识接口

课程大纲 一、定义 接口&#xff1a;外部与系统之间、内部各子系统之间的交互点。 比如日常使用的电脑&#xff0c;有电源接口、usb接口、耳机接口、显示器接口等&#xff0c;分别可以实现&#xff1a;与外部的充电、文件数据传输、声音输入输出、图像输入输出等功能。 接口的本…

262个地级市-市场潜力指数(do文件+原始文件)

全国262个地级市-市场潜力指数&#xff08;市场潜力计算方法代码数据&#xff09;_市场潜力数据分析资源-CSDN文库 市场潜力指数&#xff1a;洞察未来发展的指南针 市场潜力指数是一个综合性的评估工具&#xff0c;它通过深入分析市场需求、竞争环境、政策支持和技术创新等多个…

(2)滑动窗口算法练习:无重复字符的最长子串

无重复字符的最长子串 题目链接&#xff1a;3. 无重复字符的最长子串 - 力扣&#xff08;LeetCode&#xff09; 给定一个字符串 s &#xff0c;请你找出其中不含有重复字符的最长子串的长度。 输入: s "abcabcbb" 输出: 3 解释: 因为无重复字符的最长子串是"a…

mov视频怎么改成mp4?把mov改成MP4的四个方法

mov视频怎么改成mp4&#xff1f;选择合适的视频格式对于确保内容质量和流通性至关重要。尽管苹果公司的mov格式因其出色的视频表现备受赞誉&#xff0c;但在某些情况下&#xff0c;它并非最佳选择&#xff0c;因为使用mov格式可能面临一些挑战。MP4格式在各种设备&#xff08;如…