ClickHouse性能优化 3

简介: ClickHouse性能优化

4 ClickHouse查询优化

4.1 单表查询

4.1.1 Prewhere 替代 where

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

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


where:先将所有数据所有行取出,然后用 where 后的条件进行匹配

Prewhere:先将进行 Prewhere 后的所有字段的列取出,然后将查询语句中使用到的字段,进行补全,然后再使用 Prewhere 的条件进行匹配,从而少读取了一些用不到的字段


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

#关闭 where 自动转 prewhere(默认情况下, where 条件会自动优化成 prewhere)
set optimize_move_to_prewhere=0; 
# 使用 where
select WatchID, 
JavaEnable, 
Title, 
……
from datasets.hits_v1 where UserID='3198390223272470366';
# 使用 prewhere 关键字
select WatchID, 
JavaEnable, 
Title,
……
from datasets.hits_v1 prewhere UserID='3198390223272470366';

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


使用常量表达式

使用默认值为 alias 类型的字段

包含了 arrayJOIN,globalIn,globalNotIn 或者 indexHint 的查询

select 查询的列字段和 where 的谓词相同

使用了主键字段

4.1.2 数据采样

通过采样运算可极大提升数据分析的性能—— SAMPLE N,其中 0≥N≥1, 0即为 0%,1即为 100%,以此类推

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 表中才有效,且在创建表时需要指定采样策略。

4.1.3 列裁剪与分区裁剪

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

反例:
select * from datasets.hits_v1;
正例:
select WatchID, 
JavaEnable, 
Title, 
……
from datasets.hits_v1;

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

select WatchID,
JavaEnable, 
Title, 
……
from datasets.hits_v1
where EventDate='2014-03-23';

4.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

4.1.5 避免构建虚拟列

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

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

4.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

4.1.7 使用物化视图

  • SQL 的视图:只是把复杂的查询逻辑记录下来的,但是并没有保存对应的数据
  • 物化视图:不仅把查询逻辑记录下来,还记录下来数据

4.1.8 其他注意事项

查询熔断

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

关闭虚拟内存

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

配置 join_use_nulls

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

批量写入时先排序

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

关注 CPU

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

4.2 多表关联

4.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;

4.2.2 用 IN 代替 JOIN

  • ClickHouse 处理 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;

4.2.3 大小表 JOIN

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


小表在右

insert into table hits_v2
select a.* from hits_v1 a left join visits_v2 b on a. CounterID=b.CounterID;
  1. 大表在右
insert into table hits_v2
select a.* from visits_v2 b left join hits_v1 a on a. CounterID=b.CounterID;

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

ClickHouse 在 join 查询时不会主动发起谓词下推的操作需要每个子查询提前完成过滤操作,也就是需要在 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;

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


4.2.6 使用字典表

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


4.2.7 多表查询小结

Join 原理:先把右表加载到内存,再去一一匹配左表

非必要不使用 Join

若不得不使用到 Join,优化方式:

将小表放右边

能过滤的先过滤,特别是针对右表

特殊场景可以考虑使用字典表

目录
相关文章
|
5月前
|
存储 关系型数据库 MySQL
【性能优化】MySql查询性能优化必知必会
【性能优化】MySql查询性能优化必知必会
85 0
【性能优化】MySql查询性能优化必知必会
|
4天前
|
存储 缓存 数据库
InfluxDB性能优化:写入与查询调优
【4月更文挑战第30天】本文探讨了InfluxDB的性能优化,主要分为写入和查询调优。写入优化包括批量写入、调整写入缓冲区、数据压缩、shard配置优化和使用HTTP/2协议。查询优化涉及索引优化、查询语句调整、缓存管理、分区与分片策略及并发控制。根据实际需求应用这些策略,可有效提升InfluxDB的性能。
|
4天前
|
缓存 关系型数据库 MySQL
MySQL数据库性能优化实战
【4月更文挑战第30天】本文探讨了MySQL性能优化实战技巧,包括硬件与配置优化(如使用SSD、增加内存和调整配置参数)、索引优化(创建合适索引、使用复合索引及定期维护)、查询优化(避免全表扫描、减少JOIN和使用LIMIT)、分区与分片(表分区和数据库分片),以及使用缓存、定期清理数据库和监控诊断。通过这些方法,可以提升数据库性能和响应速度。
|
8月前
|
存储 SQL 固态存储
ClickHouse性能优化 2
ClickHouse性能优化
314 0
|
8月前
|
存储 SQL HIVE
ClickHouse性能优化 1
ClickHouse性能优化
151 0
|
SQL 存储 运维
PolarDB 大表场景性能优化技术揭秘
**背景** 很多时候业务架构设计里面最重要的一环就是数据库模型设计, 由于单机MySQL 的限制, 很多业务架构师不得不考虑对大表进行拆分, 通过中间件或者其他手段进行分库分表. 很多业务在快速发展阶段,开始考虑数据拆分的原因其实并不是计算能力遇到了瓶颈,而是海量数据的存储到达了单实例的上限,但是由于最初设计的时候没有考虑到海量数据的使用方式,或是在业务逻辑中,数据无法进行清理或归档。 运
246 0
|
SQL 缓存 分布式计算
Flinksql性能优化
Flinksql性能优化
Flinksql性能优化
|
缓存 弹性计算 监控
Cassandra性能压测及调优实战|学习笔记
快速学习Cassandra性能压测及调优实战
160 0
Cassandra性能压测及调优实战|学习笔记
|
缓存 运维 监控
Cassandra 性能压测及调优实战
掌握Cassandra分布式数据库性能压测及性能调优 作者:孤池
3423 0
Cassandra 性能压测及调优实战
|
SQL 关系型数据库 MySQL
PolarDB-X性能优化之执行计划基础
介绍一下PolarDB-X的执行计划及如何查看执行计划
424 0