大多数数据环境包括两类数据对象,基于事件对象和基于实体对象(包括属性或特征)。前者通常组织为时间序列表,后者通常基于ID表,基于行存储。这类模型称为星型规范化模型,该结构存储效率高,但读性能低。必要时采用非规范化结构会提升性能。

星型模型

下面探究ClickHouse如何使用join查询星型模型数据。假设有两张表:log(时间序列事件)、users(包括特征的实体):

log事件表使用user_id引用users表,事件log表有250m行数据,结构如下:

CREATE TABLE log (dt DateTime, user_id UInt64, session_id UInt64, platform String, label String, url String)
ENGINE = MergeTree ORDER BY (dt, user_id, session_id)

需要提醒的是:特征表通常需要修改(通常需增加、删除或修改数据),而事件表为历史静态数据(数据仅追加,不会改变)。为简化目的,users表结构如下:

CREATE TABLE users
(`id` UInt64, `name` String, `category` String, `age` UInt8 )
ENGINE = MergeTree ORDER BY (category, id)

插入演示数据:

insert into users
select number , randomPrintableASCII(5) as name,array('aa','bb','cc')[(number)%3+1] as c, number%60+18 as age
from numbers(2500000) n ;

连续执行10次log表生成测试数据:

insert into log
select (now() - number) dt , number id , number+1 sid,array('win','mac','linux')[(number)%3+1] as c,randomPrintableASCII(5)  as label,randomPrintableASCII(10) as url
from numbers(2500000) n ;select count(*) from log;

星型join

下面尝试实际示例——查询某类型用户及其年龄在特定范围的事件:

SELECT date(dt) AS day, count(*) FROM log l
JOIN users u ON u.id = l.user_id
WHEREu.category = 'aa' AND u.age > 50 AND dt > NOW() - INTERVAL 1 YEAR
GROUP BY day ORDER BY day DESC LIMIT 5

log表有250m行,用户大概25m行,查询结果如下:

┌────────day─┬─count()─┐
│ 2023-04-28 │   86546 │
│ 2023-04-27 │  129600 │
│ 2023-04-26 │  129600 │
│ 2023-04-25 │  129600 │
│ 2023-04-24 │  129600 │
└────────────┴─────────┘5 rows in set. Elapsed: 1.564 sec. Processed 27.50 million rows, 350.00 MB (17.59 million rows/s., 223.83 MB/s.)

下面通过explain查询执行情况:

EXPLAIN
SELECT date(dt) AS day, count(*) FROM log l
JOIN users u ON u.id = l.user_id
WHEREu.category = 'aa' AND u.age > 50 AND dt > NOW() - INTERVAL 1 YEAR
GROUP BY day ORDER BY day DESC LIMIT 5

使用in代替join

大多数场景可以使用in代替join,但要确保嵌套表不要返回太多数据,不能超过ClickHouse有效内存量。在我们的示例中,过滤users返回数据约为总量的15%。

SELECT count(*)
FROM users
WHERE (category = 'aa') AND (age > 50)Query id: f54846e0-65c3-44d2-8c05-1927adb28ef4┌─count()─┐
│  374997 │
└─────────┘1 rows in set. Elapsed: 0.014 sec. Processed 835.58 thousand rows, 10.03 MB (60.45 million rows/s., 725.45 MB/s.)

下面使用in代替join:

SELECTdate(dt) AS day,count(*)
FROM log
WHERE (user_id IN (SELECT idFROM usersWHERE (category = 'aa') AND (age > 50)
)) AND (dt > (NOW() - toIntervalYear(1)))
GROUP BY day
ORDER BY day DESC
LIMIT 5Query id: fb871262-d196-4043-9acb-65476a1ee8be┌────────day─┬─count()─┐
│ 2023-04-28 │   86546 │
│ 2023-04-27 │  129600 │
│ 2023-04-26 │  129600 │
│ 2023-04-25 │  129600 │
│ 2023-04-24 │  129600 │
└────────────┴─────────┘5 rows in set. Elapsed: 0.166 sec. Processed 25.84 million rows, 316.71 MB (155.68 million rows/s., 1.91 GB/s.)

从处理数据量和执行时间来看,有了较大提升。虽然这个示例效果不错,但我们不能确保in表达式一定有较大的性能提升,这时我们可以考虑使用反规范化。

反规范化数据

反规范化意味着基于join查询表创建单个表,下面创建并填充单个反规范化表:

CREATE TABLE log_users (`dt` DateTime, `user_id` UInt64, `session_id` UInt64,`platform` String, `label` String, `url` String,`user_name` String, `user_category` String, `user_age` UInt8
)
ENGINE = MergeTree
ORDER BY (dt, user_id, session_id, user_category, platform, label)

可以看到,我们使用了跟多排序键,从而覆盖跟多查询场景。下面填充数据:

INSERT INTO log_users
SELECT l.*, u.name, u.category, u.age
FROM log l JOIN users u ON (l.user_id = u.id)

再次执行前面的查询,性能明细有了提升:

SELECT
date(dt) As day, count(*)
FROM log_users
WHERE(user_category = 'aa') AND(user_age > 50) AND (dt > (now() - toIntervalMonth(1)))
GROUP BY day
ORDER BY day DESC
LIMIT 5Query id: 2b7575bc-1244-4042-907f-4f6ee8929ade┌────────day─┬─count()─┐
│ 2023-04-28 │   86546 │
│ 2023-04-27 │  129600 │
│ 2023-04-26 │  129600 │
│ 2023-04-25 │  129600 │
│ 2023-04-24 │  129600 │
└────────────┴─────────┘5 rows in set. Elapsed: 0.039 sec. Processed 5.25 million rows, 83.99 MB (134.61 million rows/s., 2.15 GB/s.)

显然,把所有字段放在单个表中,是一种强大的优化工具,包括:更好调优排序键和投影。但不要忘了需要更多的磁盘空间。

实时反规范化

前面示例在反规范化过程中需要等待,我们可以使用 物化视图实现实时填充:

CREATE MATERIALIZED VIEW log_users_rt (`dt` DateTime, `user_id` UInt64, `session_id` UInt64,`platform` String, `label` String, `url` String,`user_name` String, `user_category` String, `user_age` UInt8
)
ENGINE = MergeTree ORDER BY (dt, user_id, session_id) AS
SELECT l.*, u.name AS user_name, u.category AS user_category,u.age AS user_age
FROM log AS l INNER JOIN users AS u ON l.user_id = u.id

这里定义物化视图,让ClickHouse自动连接log和users表,填充连接查询结果至log_users_rt物化视图中。注意,现在ClickHouse在每次执行插入时日志时,需要join查询users,这会影响插入性能:

insert into log values(now(), 12,15,'aa', 'aa', 'http://baidu.com'),(now(), 12,15,'bb', 'bb', 'http://sina.com')INSERT INTO log FORMAT ValuesQuery id: 8c3c8034-7c9e-460d-9f32-887754aea6eaOk.2 rows in set. Elapsed: 0.533 sec.

插入耗时会更高,因此最好批量插入,且插入间隔周期更长。

使用MySQL外部表

更酷的事情,in查询可以使用MySQL表引擎,从而可以使用MySQL特性管理数据,如增加索引,更新或删除数据。

假设已经在MySQL的db数据库中创建了users表,结构保持一致,下面在ClickHouse中创建MySQL引擎表:

CREATE TABLE users_mysql
(`id` UInt64, `name` String, `category` String, `age` UInt8 )
ENGINE = MySQL('127.0.0.1:3306', 'db', 'users', 'usr', 'pwd')

现在使用MySQL外部表执行查询:

SELECT date(dt) AS day, count(*) FROM log
WHERE (user_id IN (SELECT id FROM users_mysql WHERE category = 'aa' AND age > 50
)) AND (dt > (NOW() - toIntervalYear(1)))
GROUP BY day ORDER BY day DESC LIMIT 5

注意,这里的嵌套查询在MySQL中执行,因此最好增加相应索引提升性能:

CREATE INDEX c_a ON users(category, age)

这里最好不要使用join查询,因为ClickHouse首先会从MySQL中加载数据,这仅为了数据过滤。

总结

ClickHouse中in查询大多数场景执行效果较好,另外反规范化也能提升性能。物化视图可以实现在插入阶段实时反规范化,但物化视图会增加磁盘空间、并影响插入性能。

优化ClickHouse星型模型查询性能相关推荐

  1. Oracle优化器:星型转换

    Oracle 8i中引入了星型转换(star transformation)的优化器新特性以便更有效地处理星型查询.星型查询语句多用于基于星型模型设计的数据仓库应用中.星型模型的称谓源于该种模型以图形 ...

  2. 数据仓库星型模型vs雪花模型

    一.概述 在多维分析的商业智能解决方案中,根据事实表和维度表的关系,又可将常见的模型分为星型模型和雪花型模型.在设计逻辑型数据的模型的时候,就应考虑数据是按照星型模型还是雪花型模型进行组织. 当所有维 ...

  3. OLAP+星型模型+雪花模型

    OLAP+星型模型+雪花模型 主键+外键 事实表+维度表 OLAP:联机分析技术( On-Line Analytical Processing) OLTP:On-Line Transaction Pr ...

  4. Power BI 数据模型设计及搭建——星型模型雪花模型

    前言 之前的笔记提到了<Power BI 数据模型的核心概念>,本文继续深入讨论数据模型的设计架构,同时介绍两种常用的数据模型:星型模型和雪花模型 BI 的数据模型和数仓模型有什么不同? ...

  5. 数据仓库(3)数仓建模之星型模型与维度建模

      维度建模是一种将数据结构化的逻辑设计方法,也是一种广泛应用的数仓建模方式,它将客观世界划分为度量和上下文.度量是常常是以数值形式出现,事实周围有上下文包围着,这种上下文被直观地分成独立的逻辑块,称 ...

  6. 数据仓库——数据仓库架构、维度数据建模、雪花模型和星型模型

    文章目录 一.数据仓库架构 1. 自顶向下 2. 自底向上 二.维度数据建模 三.星型模型和雪花模型 1. 星型模型 2. 雪花模型 本篇文章主要介绍了数据仓库的整体架构.数仓中常用的维度数据建模方法 ...

  7. 数仓 建模思想之星型模型、雪花模型、星座模型

    数仓 建模思想之星型模型.雪花模型.星座模型 1. 背景 在大数据开发中,数据一般是分为事实表,维度表,实体表等表. 事实表顾名思义就是记录实际发生的事情如订单表,优惠券使用表等等. 维度表,顾名思义 ...

  8. 全方位解读星型模型,雪花模型及星座模型

    ​1背景 在多维分析的商业智能解决方案中,根据事实表和维度表的关系,又可将常见的模型分为星型模型,雪花型模型及星座模型.在设计逻辑型数据的模型的时候,就应考虑数据是按照星型模型,雪花型模型还是星座模型 ...

  9. 三大数据模型:星型模型、雪花模型、星座模型

    星型模型 星型模型中只有一张事实表,以及0张或多张维表,事实表与维表通过主键外键相关联,维表之间不存在关联关系,当所有维表都关联到事实表时,整个图形非常像一种星星的结构,所以称之为"星型模型 ...

最新文章

  1. 涌现:21世纪科学的统一主题
  2. 站长们 技术不是你生存的全部
  3. PHP伪类型和伪变量
  4. MIT自然语言处理第二讲:单词计数(第一、二部分)
  5. 【pmcaff专栏】陆蔚青:漫谈商业智能
  6. KeyMob:我们做的不仅是移动广告聚合 更是靠谱
  7. URLScan工具配置方法第1/2页
  8. linux操作系统之竞态条件(时序竞态)
  9. Sqlserver备份存储过程
  10. python自动下载邮件附件_Python批量下载电子邮件附件并汇总合并Excel文件
  11. 2019 sample-free(样本不平衡)目标检测论文阅读笔记
  12. 菜鸡程序员的一天都在折腾些什么?
  13. Mugeda(木疙瘩)H5案例课—重力感应类H5-岑远科-专题视频课程
  14. 获取手机或电脑GPS位置信息(定位平台)
  15. CAPI 初探及使用小结(4)
  16. 【转】跨终端实践-天猫试戴的解决方案
  17. layui外部引入_layui use 定义js外部引用函数的方法
  18. 发那科机器人plc电池_FANUC机器人维修保养故障简析
  19. java mapper找不到resources下的mapper
  20. 【深度学习】实验6布置:图像自然语言描述生成(让计算机“看图说话”)

热门文章

  1. 基于Unity3D开发交通基础仿真模型实战
  2. 颜值高的蓝牙耳机有吗?2020五款小姐姐最爱真无线蓝牙耳机评测
  3. React中实现插槽效果的方案
  4. Wish店铺流量暴涨的秘密
  5. 解析《明日方舟》在社区中遭其他产品用户排挤的深浅层原因及如何破局
  6. python编译成exe和exe反编译成python
  7. Linux运维必备技能:如何在 Vim 中删除多行?
  8. KS8695 jtag
  9. 根据BMI(身体质量指数)显示一个人的体型
  10. vimrc的一些操作