当前位置: 首页 > news >正文

ClickHouse SQL 查询优化

单表查询

1.1 Prewhere替代where

Prewherewhere语句的作用相同用来过滤数据。不同之处在于prewhere只支持 *MergeTree 族系列引擎的表,首先会读取指定的列数据,来判断数据过滤,等待数据过滤之后再读取select 声明的列字段来补全其余属性。

当查询列明显多于筛选列时使用Prewhere可十倍提升查询性能,Prewhere会自动优化执行过滤阶段的数据读取方式,降低io操作。

在某些场合下,prewhere语句比where语句处理的数据量更少性能更高。

#关闭where自动转prewhere(默认情况下, where条件会自动优化成prewhere)
set optimize_move_to_prewhere=0; 
# 使用where
select WatchID, 
    JavaEnable, 
    Title, 
    GoodEvent, 
    EventTime, 
    EventDate, 
    CounterID, 
    ClientIP, 
    ClientIP6, 
    RegionID, 
    UserID, 
    CounterClass, 
    OS, 
    UserAgent, 
    URL, 
    Referer, 
    URLDomain, 
    RefererDomain, 
    Refresh, 
    IsRobot, 
    RefererCategories, 
    URLCategories, 
    URLRegions, 
    RefererRegions, 
    ResolutionWidth, 
    ResolutionHeight, 
    ResolutionDepth, 
    FlashMajor, 
    FlashMinor, 
    FlashMinor2
from datasets.hits_v1 where UserID='3198390223272470366';# 使用prewhere关键字
select WatchID, 
    JavaEnable, 
    Title, 
    GoodEvent, 
    EventTime, 
    EventDate, 
    CounterID, 
    ClientIP, 
    ClientIP6, 
    RegionID, 
    UserID, 
    CounterClass, 
    OS, 
    UserAgent, 
    URL, 
    Referer, 
    URLDomain, 
    RefererDomain, 
    Refresh, 
    IsRobot, 
    RefererCategories, 
    URLCategories, 
    URLRegions, 
    RefererRegions, 
    ResolutionWidth, 
    ResolutionHeight, 
    ResolutionDepth, 
    FlashMajor, 
    FlashMinor, 
    FlashMinor2
from datasets.hits_v1 prewhere UserID='3198390223272470366';

默认情况,我们肯定不会关闭where自动优化成prewhere,但是某些场景即使开启优化,也不会自动转换成prewhere,需要手动指定prewhere:

  • 使用常量表达式
  • 使用默认值为alias类型的字段
  • 包含了arrayJOIN,globalIn,globalNotIn或者indexHint的查询
  • select查询的列字段和where的谓词相同
  • 使用了主键字段

1.2 数据采样

通过采样运算可极大提升数据分析的性能

SELECT Title,count(*) AS PageViews 
FROM hits_v1
SAMPLE 0.1         #代表采样10%的数据,也可以是具体的条数
WHERE CounterID =57
GROUP BY Title
ORDER BY PageViews DESC LIMIT 1000

采样修饰符只有在MergeTree engine表中才有效,且在创建表时需要指定采样策略。

1.3 列裁剪与分区裁剪

数据量太大时应避免使用select * 操作,查询的性能会与查询的字段大小和数量成线性表换,字段越少,消耗的io资源越少,性能就会越高。

反例:
select * from datasets.hits_v1;
正例:
select WatchID, 
    JavaEnable, Title, 
    GoodEvent, 
    EventTime, 
    EventDate, 
    CounterID, 
    ClientIP, 
    ClientIP6, 
    RegionID, 
    UserID
from datasets.hits_v1;

分区裁剪就是只读取需要的分区在过滤条件中指定

select WatchID, 
    JavaEnable, Title, 
    GoodEvent, 
    EventTime, 
    EventDate, 
    CounterID, 
    ClientIP, 
    ClientIP6, 
    RegionID, 
    UserID
from datasets.hits_v1
where EventDate='2014-03-23';

1.4 orderby 结合 where、limit

千万以上数据集进行order by查询时需要搭配where条件和limit语句一起使用。

#正例:
SELECT UserID,Age
FROM hits_v1        
WHERE CounterID=57
ORDER BY Age DESC LIMIT 1000#反例:
SELECT UserID,Age
FROM hits_v1        
ORDER BY Age DESC

1.5 避免构建虚拟列

如非必须,不要在结果集上构建虚拟列,虚拟列非常消耗资源浪费性能,可以考虑在前端进行处理,或者在表中构造实际字段进行额外存储。

反例:
SELECT Income,Age,Income/Age as IncRate FROM datasets.hits_v1;
正例:拿到Income和Age后,考虑在前端进行处理,或者在表中构造实际字段进行额外存储
SELECT Income,Age FROM datasets.hits_v1;

1.6 uniqCombined替代distinct

性能可提升10倍以上,uniqCombined底层采用类似HyperLogLog算法实现能接收2%左右的数据误差可直接使用这种去重方式提升查询性能。Count(distinct )会使用uniqExact精确去重。

不建议在千万级不同数据上执行distinct去重查询,改为近似去重uniqCombined

反例:
select count(distinct rand()) from hits_v1;
正例:
SELECT uniqCombined(rand()) from  datasets.hits_v1

1.7 使用物化视图

参考第6章。

1.8 其他注意事项

(1)查询熔断

为了避免因个别慢查询引起的服务雪崩的问题,除了可以为单个查询设置超时以外,还可以配置周期熔断,在一个查询周期内,如果用户频繁进行慢查询操作超出规定阈值后将无法继续进行查询操作。

(2)关闭虚拟内存

物理内存和虚拟内存的数据交换,会导致查询变慢,资源允许的情况下关闭虚拟内存。

(3)配置join_use_nulls

为每一个账户添加 join_use_nulls 配置,左表中的一条记录在右表中不存在,右表的相应字段会返回该字段相应数据类型的默认值,而不是标准SQL中的Null值。

(4)批量写入时先排序

批量写入数据时,必须控制每个批次的数据中涉及到的分区的数量,在写入之前最好对需要导入的数据进行排序。无序的数据或者涉及的分区太多,会导致ClickHouse无法及时对新导入的数据进行合并,从而影响查询性能。

(5)关注CPU

cpu一般在50%左右会出现查询波动,达到70%会出现大范围的查询超时,cpu是最关键的指标,要非常关注。

多表关联

2.1 准备表和数据

#创建小表
CREATE TABLE visits_v2 
ENGINE = CollapsingMergeTree(Sign)
PARTITION BY toYYYYMM(StartDate)
ORDER BY (CounterID, StartDate, intHash32(UserID), VisitID)
SAMPLE BY intHash32(UserID)
SETTINGS index_granularity = 8192
as select * from visits_v1 limit 10000;#创建join结果表:避免控制台疯狂打印数据
CREATE TABLE hits_v2 
ENGINE = MergeTree()
PARTITION BY toYYYYMM(EventDate)
ORDER BY (CounterID, EventDate, intHash32(UserID))
SAMPLE BY intHash32(UserID)
SETTINGS index_granularity = 8192
as select * from hits_v1 where 1=0;

2.2 用 IN 代替 JOIN

当多表联查时查询的数据仅从其中一张表出时可考虑用 IN 操作而不是JOIN

insert into hits_v2
select a.* from hits_v1 a where a. CounterID in (select CounterID from visits_v1);#反例:使用join
insert into table hits_v2
select a.* from hits_v1 a left join visits_v1 b on a. CounterID=b. CounterID;

2.3 大小表JOIN

多表join时要满足小表在右的原则右表关联时被加载到内存中与左表进行比较,ClickHouse中无论是Left join Right join 还是 Inner join 永远都是拿着右表中的每一条记录到左表中查找该记录是否存在所以右表必须是小表。

(1)小表在右

insert into table hits_v2

select a.* from hits_v1 a left join visits_v2 b on a. CounterID=b. CounterID;

2大表在右

insert into table hits_v2

select a.* from visits_v2 b left join hits_v1 a on a. CounterID=b. CounterID;

2.4 注意谓词下推(版本差异)

ClickHouse在join查询时不会主动发起谓词下推的操作,需要每个子查询提前完成过滤操作,需要注意的是,是否执行谓词下推,对性能影响差别很大(新版本中已经不存在此问题,但是需要注意谓词的位置的不同依然有性能的差异)

Explain syntax
select a.* from hits_v1 a left join visits_v2 b on a. CounterID=b. CounterID
having a.EventDate = '2014-03-17';Explain syntax
select a.* from hits_v1 a left join visits_v2 b on a. CounterID=b. CounterID
having b.StartDate = '2014-03-17';insert into hits_v2
select a.* from hits_v1 a left join visits_v2 b on a. CounterID=b. CounterID
where a.EventDate = '2014-03-17';insert into hits_v2
select a.* from (select * from 
    hits_v1 where EventDate = '2014-03-17'
) a left join visits_v2 b on a. CounterID=b. CounterID;

2.5 分布式表使用GLOBAL

两张分布式表上的IN和JOIN之前必须加上GLOBAL关键字,右表只会在接收查询请求的那个节点查询一次,并将其分发到其他节点上。如果不加GLOBAL关键字的话,每个节点都会单独发起一次对右表的查询,而右表又是分布式表,就导致右表一共会被查询N²次(N是该分布式表的分片数量),这就是查询放大,会带来很大开销。

2.6 使用字典表

将一些需要关联分析的业务创建成字典表进行join操作,前提是字典表不宜太大,因为字典表会常驻内存

2.7 提前过滤

通过增加逻辑过滤可以减少数据扫描,达到提高执行速度及降低内存消耗的目的

相关文章:

ClickHouse SQL 查询优化

1 单表查询 1.1 Prewhere替代where Prewhere和where语句的作用相同,用来过滤数据。不同之处在于prewhere只支持 *MergeTree 族系列引擎的表,首先会读取指定的列数据,来判断数据过滤,等待数据过滤之后再读取select 声明的列字段来补…...

「Verilog学习笔记」数据选择器实现逻辑电路

专栏前言 本专栏的内容主要是记录本人学习Verilog过程中的一些知识点,刷题网站用的是牛客网 分析 将变量A、B接入4选1数据选择器选择输入端S0 S1。将变量C分配在数据输入端。从表中可以看出输出L与变量C的关系。 当AB00时选通D0而此时L0,所以数据端D0接0…...

【Go入门】Web工作方式

【Go入门】 Web工作方式 我们平时浏览网页的时候,会打开浏览器,输入网址后按下回车键,然后就会显示出你想要浏览的内容。在这个看似简单的用户行为背后,到底隐藏了些什么呢? 对于普通的上网过程,系统其实是这样做的&…...

综述:目标检测二十年(机翻版)(未完

原文地址 20年来的目标检测:一项调查 摘要关键词一 介绍二 目标检测二十年A.一个目标检测的路线图1)里程碑:传统探测器Viola Jones探测器HOG检测器基于可变形零件的模型(DPM) 2)里程碑:基于CNN的两阶段探测器RCNNSPPN…...

quinn源码解析:QUIC数据包是如何发送的

quinn源码解析:QUIC数据包是如何发送的 简介QUIC协议中的概念endpoint(端点)connection(连接)Stream(流)Frame (帧) 发包过程解析SendStream::write_allConnectionDriverEndpointDriver 简介 q…...

scss的高级用法——循环

周末愉快呀!一起来学一点简单但非常有用的css小知识。 最近在一个项目中看到以下css class写法: 了解过tailwind css或者unocss的都知道,从命名就可以看出有以下样式: font-size: 30pxmargin-left: 5px;margin-top: 10px; 于是…...

Linux安装Chrome浏览器 -linux安装choeme

Linux 操作系统一般自带的浏览器是 FireFox,不过有些用户可能更喜欢 Google 出品的 Chrome 浏览器。本教程将介绍如何在 Linux 系统上安装 Chrome 浏览器,以及可能会遇到的一些问题解决方案。 下载 Chrome 安装包 需要下载 Chrome 的安装包。可以在 Go…...

六大排序(插入排序、希尔排序、冒泡排序、选择排序、堆排序、快速排序)未完

文章目录 排序一、 排序的概念1.排序:2.稳定性:3.内部排序:4.外部排序: 二、插入排序1.直接插入排序2.希尔排序 三、选择排序1.直接选择排序方法一方法二直接插入排序和直接排序的区别 2.堆排序 四、交换排序1.冒泡排序2.快速排序…...

JVM垃圾回收相关概念

目录 一、System.gc()的理解 二、内存溢出与内存泄露 (一)OOM (二)内存泄露 三、StopTheWorld 四、垃圾回收的并行与并发 五、安全点与安全区域 (一)安全点 (二)安全区域 …...

C++各种字符转换

C各种字符转换 一.如何将char数组转化为string类型二. string转char数组:参考 一.如何将char数组转化为string类型 在C中,可以使用string的构造函数或者赋值操作符来将char数组转换为string类型。 方法1:使用string的构造函数 const char* c…...

MSSQL-逻辑级常用命令

--SQL Server 查询表的记录数 --one: 使用系统表. SELECT object_name (i.id) TableName, rows as RowCnt FROM sysindexes i INNER JOIN sysObjects o ON (o.id i.id AND o.xType U ) WHERE indid < 2 ORDER BY rows desc ————————————…...

【如何学习Python自动化测试】—— 时间等待

3 、 时间等待 在做自动化测试时&#xff0c;难免会碰到一些问题&#xff0c;比如你在脚本中操作某个对象时&#xff0c; 页面还没有加载出来&#xff0c;你的操作语句已经被执行&#xff0c;从而导致脚本执行失败&#xff0c;针对这样的问题 webdriver 提供了等待操作&#xf…...

《数字图像处理-OpenCV/Python》连载(44)图像的投影变换

《数字图像处理-OpenCV/Python》连载&#xff08;44&#xff09;图像的投影变换 本书京东优惠购书链接&#xff1a;https://item.jd.com/14098452.html 本书CSDN独家连载专栏&#xff1a;https://blog.csdn.net/youcans/category_12418787.html 第 6 章 图像的几何变换 几何变…...

AI机器学习 | 基于librosa库和使用scikit-learn库中的分类器进行语音识别

专栏集锦&#xff0c;大佬们可以收藏以备不时之需 Spring Cloud实战专栏&#xff1a;https://blog.csdn.net/superdangbo/category_9270827.html Python 实战专栏&#xff1a;https://blog.csdn.net/superdangbo/category_9271194.html Logback 详解专栏&#xff1a;https:/…...

Asp.net MVC Api项目搭建

整个解决方案按照分层思想来划分不同功能模块&#xff0c;以提供User服务的Api为需求&#xff0c;各个层次的具体实现如下所示&#xff1a; 1、新建数据库User表 数据库使用SQLExpress版本&#xff0c;表的定义如下所示&#xff1a; CREATE TABLE [dbo].[User] ([Id] …...

C语言中文网 - Shell脚本 - 8

第1章 Shell基础&#xff08;开胃菜&#xff09; 8. Linux Shell命令提示符 启动 Linux 桌面环境自带的终端模拟包&#xff0c;或者从 Linux 控制台登录后&#xff0c;便可以看到 Shell 命令提示符。看见命令提示符就意味着可以输入命令了。命令提示符不是命令的一部分&#x…...

性能测试学习——项目环境搭建和Jmete学习二

项目环境搭建、Jmeter学习二 环境的部署虚拟机的安装虚拟机中添加项目操作步骤 使用环境的注意事项Jmeter的安装和简单使用Jemter的使用的进阶Jemter元件 Jmeter属性执行顺序和作用域作用域以自定义用户变量和用户参数(前置处理器)为例如何解决用户变量和线程组同级时&#xff…...

C++标准模板库(STL)-map介绍

C标准库中的map是一种关联容器&#xff0c;它提供了键值对的映射关系。每个键值对中的键都是唯一的&#xff0c;通过键可以访问对应的值。 map基本操作 插入元素&#xff1a; 使用insert函数插入元素&#xff0c;该函数有两种形式&#xff1a; // 插入一个pair<const Ke…...

使用docker部署ELK日志框架-Elasticsearch

一、ELK知识了解 1-ELK组件 工作原理&#xff1a; &#xff08;1&#xff09;在所有需要收集日志的服务器上部署Logstash&#xff1b;或者先将日志进行集中化管理在日志服务器上&#xff0c;在日志服务器上部署 Logstash。 &#xff08;2&#xff09;Logstash 收集日志&#…...

第7章 模式匹配与正则表达式

目录 1. 不用正则表达式来查找文本模式2. 用正则表达式来查找文本模式2.1 创建正则表达式&#xff08;Regex&#xff09;对象2.2 匹配Regex对象 3. 用正则表达式匹配更多模式3.1 利用括号分组3.2 用管道匹配多个分组3.3 用问号实现可选匹配3.4 用星号匹配零次或多次3.5 用加号匹…...

Android Wi-Fi 连接失败日志分析

1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分&#xff1a; 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析&#xff1a; CTR…...

<6>-MySQL表的增删查改

目录 一&#xff0c;create&#xff08;创建表&#xff09; 二&#xff0c;retrieve&#xff08;查询表&#xff09; 1&#xff0c;select列 2&#xff0c;where条件 三&#xff0c;update&#xff08;更新表&#xff09; 四&#xff0c;delete&#xff08;删除表&#xf…...

React Native 开发环境搭建(全平台详解)

React Native 开发环境搭建&#xff08;全平台详解&#xff09; 在开始使用 React Native 开发移动应用之前&#xff0c;正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南&#xff0c;涵盖 macOS 和 Windows 平台的配置步骤&#xff0c;如何在 Android 和 iOS…...

Admin.Net中的消息通信SignalR解释

定义集线器接口 IOnlineUserHub public interface IOnlineUserHub {/// 在线用户列表Task OnlineUserList(OnlineUserList context);/// 强制下线Task ForceOffline(object context);/// 发布站内消息Task PublicNotice(SysNotice context);/// 接收消息Task ReceiveMessage(…...

QMC5883L的驱动

简介 本篇文章的代码已经上传到了github上面&#xff0c;开源代码 作为一个电子罗盘模块&#xff0c;我们可以通过I2C从中获取偏航角yaw&#xff0c;相对于六轴陀螺仪的yaw&#xff0c;qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题

在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件&#xff0c;这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下&#xff0c;实现高效测试与快速迭代&#xff1f;这一命题正考验着…...

Reasoning over Uncertain Text by Generative Large Language Models

https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...

莫兰迪高级灰总结计划简约商务通用PPT模版

莫兰迪高级灰总结计划简约商务通用PPT模版&#xff0c;莫兰迪调色板清新简约工作汇报PPT模版&#xff0c;莫兰迪时尚风极简设计PPT模版&#xff0c;大学生毕业论文答辩PPT模版&#xff0c;莫兰迪配色总结计划简约商务通用PPT模版&#xff0c;莫兰迪商务汇报PPT模版&#xff0c;…...

Golang——9、反射和文件操作

反射和文件操作 1、反射1.1、reflect.TypeOf()获取任意值的类型对象1.2、reflect.ValueOf()1.3、结构体反射 2、文件操作2.1、os.Open()打开文件2.2、方式一&#xff1a;使用Read()读取文件2.3、方式二&#xff1a;bufio读取文件2.4、方式三&#xff1a;os.ReadFile读取2.5、写…...

适应性Java用于现代 API:REST、GraphQL 和事件驱动

在快速发展的软件开发领域&#xff0c;REST、GraphQL 和事件驱动架构等新的 API 标准对于构建可扩展、高效的系统至关重要。Java 在现代 API 方面以其在企业应用中的稳定性而闻名&#xff0c;不断适应这些现代范式的需求。随着不断发展的生态系统&#xff0c;Java 在现代 API 方…...