惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 叶小钗
云风的 BLOG
云风的 BLOG
G
Google Developers Blog
S
SegmentFault 最新的问题
罗磊的独立博客
Hugging Face - Blog
Hugging Face - Blog
美团技术团队
爱范儿
爱范儿
博客园 - 三生石上(FineUI控件)
H
Hackread – Cybersecurity News, Data Breaches, AI and More
D
DataBreaches.Net
F
Fortinet All Blogs
TaoSecurity Blog
TaoSecurity Blog
D
Docker
C
Cybersecurity and Infrastructure Security Agency CISA
K
Kaspersky official blog
宝玉的分享
宝玉的分享
腾讯CDC
Google Online Security Blog
Google Online Security Blog
Recorded Future
Recorded Future
T
The Exploit Database - CXSecurity.com
T
The Blog of Author Tim Ferriss
V
V2EX
S
Securelist
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
C
CERT Recently Published Vulnerability Notes
A
Arctic Wolf
Scott Helme
Scott Helme
L
LINUX DO - 热门话题
Y
Y Combinator Blog
P
Proofpoint News Feed
T
Tor Project blog
AWS News Blog
AWS News Blog
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
The Last Watchdog
The Last Watchdog
博客园 - 聂微东
T
Threat Research - Cisco Blogs
B
Blog
Attack and Defense Labs
Attack and Defense Labs
L
Lohrmann on Cybersecurity
C
CXSECURITY Database RSS Feed - CXSecurity.com
阮一峰的网络日志
阮一峰的网络日志
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
IT之家
IT之家
N
News and Events Feed by Topic
博客园 - 司徒正美
H
Help Net Security
C
Cisco Blogs
C
Check Point Blog
S
Secure Thoughts

ClickHouse

有没有熟悉 clickhouse 的? clickhouse 对于分布式支持的如何? ClickHouse 的 MaterializedMySQL 引擎 - V2EX 两条数据库创建语句产生了同样的效果 CREATE DATABASE hello1; 与 CREATE DATABASE hello ON CLUSTER 'xxxxx'; 大佬们,我又来了!群晖装 clickhouse,撑得住吗? 究竟是什么在占用着内存 求大佬优化 3000w 数据多 UNION clickhouse 文档里的划分冷热多盘存储配置真的是按时间划分冷热数据的吗? - V2EX 请教各位大佬关于 clickhouse 的问题 - V2EX 我这个场景, clickhouse 适用吗? - V2EX
求大佬优化一下 3000 万数据的 NOT IN 查询
sunrealzhang · 2023-12-13 · via ClickHouse

这是一个创建于 913 天前的主题,其中的信息可能已经有所发展或是发生改变。

我有一个 3000w 行的数据表,我需要在这个表上统计从某一年开始新参保的人数,原数据库是 ORACLE ,用的是

AND A.AAC001 NOT EXISTS
(SELECT 1
FROM AC02_TEMP AS B WHERE A.AAC001 = B.AAC001 AND
B.AAC030 < '2018-01-01 00:00:00')

的语法,在 clickhouse 上我试了 LEFT JOIN 和 NOT IN ,性能均不理想

SELECT COUNT(1)  AS "新参保人数"
FROM AC02_TEMP AS A
WHERE A.AAB301 IN (SELECT AAB301 FROM AA26 WHERE AAA148 = '130800')
AND A.AAE200 = '41'
AND A.AAC031 = '1'
AND A.AAC030 >= '2018-01-01 00:00:00'
AND A.AAC001 NOT IN
(SELECT B.AAC001
FROM AC02_TEMP AS B
WHERE B.AAC030 < '2018-01-01 00:00:00');

以下是 explain

CreatingSets (Create sets before main query execution)
  Expression ((Projection + Before ORDER BY))
    Aggregating
      Expression (Before GROUP BY)
        ReadFromMergeTree (default.AC02_TEMP)
        Indexes:
          PrimaryKey
            Keys: 
              AAC001
              AAE200
"            Condition: and((AAC001 notIn 18692488-element set), (AAE200 in ['41', '41']))"
            Parts: 2/2
            Granules: 4821/4821
  CreatingSet (Create set for subquery)
    Expression ((Projection + Before ORDER BY))
      ReadFromMergeTree (default.AA26)
      Indexes:
        PrimaryKey
          Condition: true
          Parts: 1/1
          Granules: 1/1

我是 clickhouse 新手,目前没什么头绪,求大佬帮助 0.0

pushMeUp

2

pushMeUp      2023 年 12 月 13 日

这样子可以不?
SELECT
COUNT( 1 ) AS "新参保人数"
FROM
AC02_TEMP AS A
LEFT JOIN ( SELECT B.AAC001 AS TID FROM AC02_TEMP AS B WHERE B.AAC030 < '2018-01-01 00:00:00' ) AS t0 ON t0.AAC001 = A.AAC001
WHERE
A.AAB301 IN ( SELECT AAB301 FROM AA26 WHERE AAA148 = '130800' )
AND A.AAE200 = '41'
AND A.AAC031 = '1'
AND A.AAC030 >= '2018-01-01 00:00:00'
AND t0.TID IS NULL

OOKAMI

3

OOKAMI      2023 年 12 月 13 日

用 UNION ALL 来做减法汇总试试?

SELECT SUM(CNT)
FROM (SELECT COUNT(1) AS CNT
FROM AC02_TEMP AS A
WHERE A.AAB301 IN (SELECT AAB301 FROM AA26 WHERE AAA148 = '130800')
AND A.AAE200 = '41'
AND A.AAC031 = '1'
AND A.AAC030 >= '2018-01-01 00:00:00'

UNION ALL
SELECT -1 * COUNT(1) AS CNT
FROM AC02_TEMP AS A
WHERE A.AAB301 IN (SELECT AAB301 FROM AA26 WHERE AAA148 = '130800')
AND A.AAE200 = '41'
AND A.AAC031 = '1'
AND A.AAC030 >= '2018-01-01 00:00:00'
AND EXISTS (SELECT FROM AC02_TEMP AS B
WHERE B.AAC001 = A.AAC001
AND B.AAC030 < '2018-01-01 00:00:00'));

sunrealzhang

4

sunrealzhang      2023 年 12 月 13 日

@sss15 感谢您的回复,首先连接处应该是 ON t0.TID = A.AAC001 ,然后,AAC001 是这张表的联合主键之一,类型为 Int64 ,未关联上时值不是 NULL 而是 0 (这一点我也不知道为什么要这么实现,按理说未关联上不应该是 NULL 吗),然后我执行了 该查询,依然很慢
```
EXPLAIN indexes = 1 SELECT
COUNT( 1 ) AS "新参保人数"
FROM
AC02_TEMP AS A
LEFT JOIN ( SELECT B.AAC001 AS TID FROM AC02_TEMP AS B WHERE B.AAC030 < '2018-01-01 00:00:00' ) AS t0 ON t0.TID = A.AAC001
WHERE
A.AAB301 IN ( SELECT AAB301 FROM AA26 WHERE AAA148 = '130800' )
AND A.AAE200 = '41'
AND A.AAC031 = '1'
AND A.AAC030 >= '2018-01-01 00:00:00'
AND t0.TID = 0;
```

执行计划
```
CreatingSets (Create sets before main query execution)
Expression ((Projection + Before ORDER BY))
Aggregating
Expression (Before GROUP BY)
Filter (WHERE)
Join (JOIN FillRightFirst)
Filter (( + Before JOIN))
ReadFromMergeTree (default.AC02_TEMP)
Indexes:
PrimaryKey
Keys:
AAE200
" Condition: (AAE200 in ['41', '41'])"
Parts: 2/2
Granules: 4821/4821
Expression ((Joined actions + (Rename joined columns + (Projection + Before ORDER BY))))
ReadFromMergeTree (default.AC02_TEMP)
Indexes:
PrimaryKey
Condition: true
Parts: 2/2
Granules: 4821/4821
CreatingSet (Create set for subquery)
Expression ((Projection + Before ORDER BY))
ReadFromMergeTree (default.AA26)
Indexes:
PrimaryKey
Condition: true
Parts: 1/1
Granules: 1/1

```

sunrealzhang

5

sunrealzhang      2023 年 12 月 13 日

@OOKAMI 感谢您的回复,实际上,clickhouse 对 EXISTS 语法不完全支持,特别是子查询中无法引用外部表和列,这会导致执行时提示 Missing columns: 'A.AAC001',这也是我将 oracle 中的 NOT EXISTS 改成 NOT IN 的原因

sunrealzhang

6

sunrealzhang      2023 年 12 月 13 日

这个 sql 给我整不会了,开始感觉如果不对表结构和数据进行处理,无法通过这个数据库来满足我们的统计分析需求 0.0

9yu

7

9yu      2023 年 12 月 13 日 via iPhone

不是很懂 SQL 但是楼主的回复都很有礼貌和条理。我绝对想和楼主这样认真的人做同事。

OOKAMI

8

OOKAMI      2023 年 12 月 13 日

不懂 clickhouse ,硬要一个 SQL 出来结果的话,这个行不行,按日期分两段去重查 KEY ,再统计,最后去除重复的,这样也没有大数据集匹配

SELECT COUNT(1)
FROM (SELECT AAC001, COUNT(1) AS cnt
FROM (SELECT DISTINCT AAC001
FROM AC02_TEMP AS A
WHERE A.AAB301 IN
(SELECT AAB301 FROM AA26 WHERE AAA148 = '130800')
AND A.AAE200 = '41'
AND A.AAC031 = '1'
AND A.AAC030 >= '2018-01-01 00:00:00'
UNION ALL
SELECT DISTINCT AAC001
FROM AC02_TEMP AS A
WHERE A.AAB301 IN
(SELECT AAB301 FROM AA26 WHERE AAA148 = '130800')
AND A.AAE200 = '41'
AND A.AAC031 = '1'
AND A.AAC030 < '2018-01-01 00:00:00'))
GROUP BY AAC001)
WHERE CNT = 1;

hicdn

9

hicdn      2023 年 12 月 13 日 via Android

看场景,你是要一次性导出数据还是在业务系统里需要动态查询?

如果是一次性导出数据,直接 dump 整表,然后在 python 里用 set 加载,判断 in

Terry166

10

Terry166      2023 年 12 月 13 日

In Oracle we can only put up to 1000 values into an IN clause.
Oracle In 字句最多只能包含 1000 个值,否则影响性能。

解决方案:
1 ,用 subquery 把数据集分开处理;
2 ,创建临时表或者物理表来存储中间数据集;
3 ,用 join 来替代 in

512357301

11

512357301      2023 年 12 月 13 日 via Android

ck 的 join 是大短板,更何况是子查询。。。
子查询换成 join 试试?

Maboroshii

12

Maboroshii      2023 年 12 月 13 日

离线查出所有人的首次参保时间, 然后新增数据的时候,也新增到这个首次参保时间表? 然后直接查这个首次参保时间就可以了。

sunrealzhang

13

sunrealzhang      2023 年 12 月 14 日

@hicdn 动态查询,我们准备把 oracle 的部分可能会导致高负载的查询统计 sql 转移到统计分析类数据库 clickhouse 上

sunrealzhang

15

sunrealzhang      2023 年 12 月 14 日

@9yu 感谢您的回复,实际上在 Oracle 上我们使用的 NOT EXISTS ,我想在 clickhouse 上,我们需要在数据同步时对数据本身进行额外的预处理来缓存首次参保状态,原封不动的使用 clickhouse 来支持完成业务需求是我们的一厢情愿 0.0

sunrealzhang

18

sunrealzhang      2023 年 12 月 14 日

@OOKAMI 感谢您的回复,我仔细看了下,语义应该和我的需求不符,如果某个 AAC001 未命中第一段 join 而只命中了第二段 join ,依然能被查出来,而它并不是 2018 年开始新参保,而是 2018 年之前有过参保记录。

512357301

20

512357301      2023 年 12 月 15 日 via Android

@sunrealzhang 类型为 Int64 ,未关联上时值不是 NULL 而是 0 (这一点我也不知道为什么要这么实现,按理说未关联上不应该是 NULL 吗)

这是 ck 的特性,未关联上的,会根据字段类型返回默认值,int 是 0 ,string 是'',其他的没研究

dyv9

21

dyv9      2024 年 3 月 20 日 via Android

做报表分析就不该实时查询,先建表,将首次参保读取保存,可分段构建这个表,比如跑循环一年一年地构建。 数据仓库 dtl 软件像 pentaho kettle 可支持这种场景,还可调度任务定时处理。做报表就要放弃直接在实时查询,一定要分步骤加工数据到基本维度表,然后叠加。

kemistep

22

kemistep      5 月 15 日

使用 bitmap 查询,并且建表的时候,可以使用 hash user_id