ClickHouse性能优化 2

简介: ClickHouse性能优化

2.5 常见配置

配置项主要在 config.xml 或 users.xml 中, 基本上都在 users.xml 里

config.xml 的配置项

https://clickhouse.com/docs/en/operations/server-configuration-parameters/settings/

users.xml 的配置项

https://clickhouse.tech/docs/en/operations/settings/settings/

2.5.1 CPU 资源

image.png

2.5.2 内存资源

image.png

2.5.3 存储

ClickHouse 不支持设置多数据目录,为了提升数据 io 性能,可以挂载虚拟券组,一个券组绑定多块物理磁盘提升读写性能,多数据查询场景 SSD 会比普通机械硬盘快 2-3 倍。

3 ClickHouse语法优化规则

ClickHouse的 SQL 优化规则是基于 RBO(Rule Based Optimization),下面是一些优化规则


3.1 准备测试用表

上传官方的数据集

将 visits_v1.tar 和 hits_v1.tar 上传到虚拟机,解压到 clickhouse 数据路径下

   // 解压到 clickhouse 数据路径
   sudo tar -xvf hits_v1.tar -C /var/lib/clickhouse
   sudo tar -xvf visits_v1.tar -C /var/lib/clickhouse
   //修改所属用户
   sudo chown -R clickhouse:clickhouse /var/lib/clickhouse/data/datasets
   sudo chown -R clickhouse:clickhouse /var/lib/clickhouse/metadata/datasets
  1. 重启 clickhouse-server
sudo clickhouse restart
  1. 执行查询
   clickhouse-client --query "SELECT COUNT(*) FROM datasets.hits_v1"
   clickhouse-client --query "SELECT COUNT(*) FROM datasets.visits_v1"

注意:官方的 tar 包,包含了建库、建表语句、数据内容,这种方式不需要手动建库、建表,最方便。

hits_v1 表有 130 多个字段,880 多万条数据

visits_v1 表有 180 多个字段,160 多万条数据


3.2 COUNT 优化

在调用 count 函数时,如果使用的是 count() 或者 count(*),且没有 where 条件,则会直接使用 system.tables 的 total_rows,例如:

EXPLAIN SELECT count()FROM datasets.hits_v1;
Union
  Expression (Projection)
    Expression (Before ORDER BY and SELECT)
      MergingAggregated
        ReadNothing (Optimized trivial count)

注意 Optimized trivial count ,这是对 count 的优化, 只要括号中不写具体的字段就会进行优化

如果 count 具体的列字段,则不会使用此项优化:

EXPLAIN SELECT count(CounterID) FROM datasets.hits_v1;
Union
  Expression (Projection)
    Expression (Before ORDER BY and SELECT)
      Aggregating
        Expression (Before GROUP BY)
          ReadFromStorage (Read from MergeTree)

3.3 消除子查询重复字段

  • 下面语句子查询中有两个重复的 id 字段,会被去重:
  EXPLAIN SYNTAX SELECT 
      a.UserID,
      b.VisitID,
      a.URL,
      b.UserID
    FROM
      hits_v1 AS a 
    LEFT JOIN ( 
      SELECT 
        UserID, 
        UserID as HaHa, 
        VisitID 
      FROM visits_v1) AS b 
      USING (UserID)
    limit 3;
  • 返回优化语句:
  SELECT 
    UserID,
    VisitID,
    URL,
    b.UserID
  FROM hits_v1 AS a
  ALL LEFT JOIN 
  (
    SELECT 
    UserID,
    VisitID
    FROM visits_v1
  ) AS b USING (UserID)
  LIMIT 3

3.4 谓词下推

当 group by 有 having 子句,但是没有 with cube、with rollup 或者 with totals 修饰的时候,having 过滤会下推到 where 提前过滤。例如下面的查询,HAVING name 变成了 WHERE name,在 group by 之前过滤:

EXPLAIN SYNTAX 
  SELECT UserID 
  FROM hits_v1 
  GROUP BY UserID 
  HAVING UserID = '8585742290196126178';
//返回优化语句
SELECT UserID
FROM hits_v1
WHERE UserID = \'8585742290196126178\'
GROUP BY UserID

子查询也支持谓词下推:

EXPLAIN SYNTAX
SELECT *
FROM 
(
  SELECT UserID
  FROM visits_v1
)
WHERE UserID = '8585742290196126178'
//返回优化后的语句
SELECT UserID
FROM 
(
  SELECT UserID
  FROM visits_v1
  WHERE UserID = \'8585742290196126178\'
)
WHERE UserID = \'8585742290196126178\'

再来一个复杂例子:

EXPLAIN SYNTAX
  SELECT * FROM (
    SELECT * 
    FROM 
    (
      SELECT  UserID 
      FROM visits_v1
    ) 
    UNION ALL 
    SELECT *
    FROM
    (
      SELECT UserID 
      FROM visits_v1
    )
  )
  WHERE UserID = '8585742290196126178'
//返回优化后的语句
SELECT UserID
FROM 
  (
    SELECT UserID
    FROM 
    (
      SELECT UserID
      FROM visits_v1
      WHERE UserID = \'8585742290196126178\'
    )
    WHERE UserID = \'8585742290196126178\'
    UNION ALL
    SELECT UserID
    FROM 
    (
      SELECT UserID
      FROM visits_v1
      WHERE UserID = \'8585742290196126178\'
    )
    WHERE UserID = \'8585742290196126178\'
  )
WHERE UserID = \'8585742290196126178\'

3.5 聚合计算外推

聚合函数内的计算,会外推,例如:

EXPLAIN SYNTAX
SELECT sum(UserID * 2)
FROM visits_v1
//返回优化后的语句
SELECT sum(UserID) * 2
FROM visits_v1

3.6 聚合函数消除

如果对聚合键,也就是 group by key 使用 min、max、any 聚合函数,则将函数消除,

例如:

EXPLAIN SYNTAX
SELECT
  sum(UserID * 2),
  max(VisitID),
  max(UserID)
FROM visits_v1
GROUP BY UserID
//返回优化后的语句
SELECT
  sum(UserID) * 2,
  max(VisitID),
  UserID
FROM visits_v1
GROUP BY UserID

3.7 删除重复的 order by key

例如下面的语句,重复的聚合键 id 字段会被去重:

EXPLAIN SYNTAX
  SELECT *
  FROM visits_v1
  ORDER BY
    UserID ASC,
    UserID ASC,
    VisitID ASC,
    VisitID ASC
//返回优化后的语句:
select ……
FROM visits_v1
ORDER BY 
  UserID ASC,
  VisitID ASC

3.8 删除重复的 limit by key

例如下面的语句,重复声明的 name 字段会被去重:

EXPLAIN SYNTAX
  SELECT *
  FROM visits_v1
  LIMIT 3 BY
    VisitID,
    VisitID
  LIMIT 10
//返回优化后的语句:
select ……
FROM visits_v1
LIMIT 3 BY VisitID
LIMIT 10

3.9 删除重复的 USING Key

例如下面的语句,重复的关联键 id 字段会被去重:

EXPLAIN SYNTAX
  SELECT
    a.UserID,
    a.UserID,
    b.VisitID,
    a.URL,
    b.UserID
  FROM hits_v1 AS a
  LEFT JOIN visits_v1 AS b USING (UserID, UserID)
//返回优化后的语句:
SELECT 
  UserID,
  UserID,
  VisitID,
  URL,
  b.UserID
FROM hits_v1 AS a
ALL LEFT JOIN visits_v1 AS b USING (UserID)

3.10 标量替换

如果子查询只返回一行数据,在被引用的时候用标量替换,例如下面语句中的 total_disk_usage 字段:

EXPLAIN SYNTAX
WITH 
  (
    SELECT sum(bytes)
    FROM system.parts
    WHERE active
  ) AS total_disk_usage
SELECT
  (sum(bytes) / total_disk_usage) * 100 AS table_disk_usage, table
FROM system.parts
GROUP BY table
ORDER BY table_disk_usage DESC
LIMIT 10;
//返回优化后的语句:
WITH CAST(0, \'UInt64\') AS total_disk_usage
SELECT 
  (sum(bytes) / total_disk_usage) * 100 AS table_disk_usage, table
FROM system.parts
GROUP BY table
ORDER BY table_disk_usage DESC
LIMIT 10

3.11 三元运算优化

如果开启了 optimize_if_chain_to_multiif 参数,三元运算符会被替换成 multiIf 函数,

例如:

EXPLAIN SYNTAX 
  SELECT number = 1 ? 'hello' : (number = 2 ? 'world' : 'oldlu') 
  FROM numbers(10) 
  settings optimize_if_chain_to_multiif = 1;
//返回优化后的语句:
SELECT multiIf(number = 1, \'hello\', number = 2, \'world\', \'oldlu\')
FROM numbers(10)
SETTINGS optimize_if_chain_to_multiif = 1
目录
相关文章
|
7月前
|
存储 关系型数据库 MySQL
【性能优化】MySql查询性能优化必知必会
【性能优化】MySql查询性能优化必知必会
123 0
【性能优化】MySql查询性能优化必知必会
|
SQL 存储 算法
ClickHouse性能优化 3
ClickHouse性能优化
489 0
|
存储 NoSQL 算法
8个 数据库性能优化方案,你知道几个?(建议收藏) 上
8个 数据库性能优化方案,你知道几个?(建议收藏) 上
1598 0
8个 数据库性能优化方案,你知道几个?(建议收藏) 上
|
1月前
|
存储 SQL 缓存
优化ClickHouse查询性能:最佳实践与调优技巧
【10月更文挑战第26天】在大数据分析领域,ClickHouse 以其卓越的查询性能和高效的列式存储机制受到了广泛的关注。作为一名已经有一定 ClickHouse 使用经验的开发者,我深知在实际应用中,合理的表设计、索引优化以及查询优化对于提升 ClickHouse 性能的重要性。本文将结合我的实践经验,分享一些有效的优化策略。
123 3
|
7月前
|
存储 缓存 数据库
InfluxDB性能优化:写入与查询调优
【4月更文挑战第30天】本文探讨了InfluxDB的性能优化,主要分为写入和查询调优。写入优化包括批量写入、调整写入缓冲区、数据压缩、shard配置优化和使用HTTP/2协议。查询优化涉及索引优化、查询语句调整、缓存管理、分区与分片策略及并发控制。根据实际需求应用这些策略,可有效提升InfluxDB的性能。
1840 1
|
存储 NoSQL 数据建模
MongoDB性能系列最佳实践-数据建模与内存优化
帮助用户在多个关键方面实现规模化性能优化
MongoDB性能系列最佳实践-数据建模与内存优化
|
存储 SQL HIVE
ClickHouse性能优化 1
ClickHouse性能优化
277 0
|
存储 缓存 运维
8个 数据库性能优化方案,你知道几个?(建议收藏) 下
8个 数据库性能优化方案,你知道几个?(建议收藏) 下
223 0
8个 数据库性能优化方案,你知道几个?(建议收藏) 下
|
SQL 关系型数据库 MySQL
PolarDB 大表场景性能优化技术揭秘
**背景** 很多时候业务架构设计里面最重要的一环就是数据库模型设计, 由于单机MySQL 的限制, 很多业务架构师不得不考虑对大表进行拆分, 通过中间件或者其他手段进行分库分表. 很多业务在快速发展阶段,开始考虑数据拆分的原因其实并不是计算能力遇到了瓶颈,而是海量数据的存储到达了单实例的上限,但是由于最初设计的时候没有考虑到海量数据的使用方式,或是在业务逻辑中,数据无法进行清理或归档。 运
304 0
|
SQL 关系型数据库 MySQL
PolarDB-X性能优化之执行计划基础
介绍一下PolarDB-X的执行计划及如何查看执行计划
528 0