// 查看执行计划,默认值
EXPLAIN PLAN SELECT arrayJoin([6,6,7])
// AST语法树查看
EXPLAIN AST SELECT numbers FROM system.numbers LIMIT 10;
// 用于优化语法
EXPLAIN SYNTAX SELECT arrayJoin([6,6,7])
// 查看PIPELINE计划
EXPLAIN PIPELINE SELECT arrayJoin([6,6,7])
分区粒度根据根据业务特点决定,不宜过粗过细。一般选择按天分区。必须指定索引列,ClickHouse中索引列即排序列,通过order by指定。组合索引需满足查询频率大在前。基数特别大的列不适宜做索引列
如果使用的是count()或count(*),只要没指定具体字段,且没有where条件,则会直接使用system.tables的total_rows:
SELECT COUNT() FROM datasets.hits_vl;
EXPLAIN SYNTAX SELECT UserID FROM hits_v1 GROUP BY UserID Having UserID='111';
会被自动优化为
EXPLAIN SYNTAX SELECT UserID FROM hits_v1 WHERE UserID='111' GROUP BY UserID;
EXPLAIN SYNTAX SELECT SUM(UserID*2) FROM visits_v1;
会被自动优化为
SELECT SUM(UserID) * 2 FROM visits_v1;
EXPLAIN SYNTAX SELECT SUM(UserID*2),max(VisitID), max(UserID) FROM visits_v1 GROUP BY UserID;
会被自动优化为
EXPLAIN SYNTAX SELECT SUM(UserID) * 2, max(VisitID), UserID FROM visits_v1 GROUP BY UserID;
EXPLAIN SYNTAX SELECT number=1?'hello':(number=2?'world':'china') FROM numbers(10) SETTINGS optimize_if_chain_to_multiif=1;
返回优化后的语句:
─explain───────────────────────────────────────────────────────────┐
│ SELECT multiIf(number = 1, 'hello', number = 2, 'world', 'china') │
│ FROM numbers(10) │
│ SETTINGS optimize_if_chain_to_multiif = 1 │
└───────────────────────────────────────────────────────────────────┘
prewhere和where语句的作用相同,用来过滤数据。不同之处在于prewhere只支持*MergeTree族系列引擎的表,首先会读取指定的列数据,来判断数据过滤,等待数据过滤之后在读取select声明的列字段来补全其余属性。默认情况下,where条件会自动优化成prewhere。
通过采样运算可极大提升数据分析的性能
SELECT Title, count(*) AS PageViews FROM hits_v1 SAMPLE 0.1 WHERE CounterID=57 GROUP BY Title;
列裁剪即指定所需要的列,而非全量*,分区裁剪就是只读取需要的分区,在过滤条件中指定
千万以上数据集进行order by查询时需要搭配where条件和limit语句一起使用
不要在结果集上构建虚拟列,非常消耗资源降低性能。
// 反例
SELECT Income, Age, Income/Age AS Ia FROM datasets.hits_v1;
性能可提升10倍以上,uniqCombined底层采用类似HyperLogLog算法实现。不建议在千万级数据上执行distinct去重查询,改为近似去重uniqCombined。
ClickHouse的物化视图是一种查询结果的持久化。物化视图不会随着基础表的变换而变化,被称为’快照’,
如下表而言,当发布日期大于10月1日,会在物化视图的存储表.inner_id.xxxx中插入数据,而当清空基础表house时,.inner_id.xxxx中的数据并不会丢失。
// 创建物化视图
CREATE MATERIALIZED VIEW study.house_new_mv ENGINE ReplacingMergeTree PARTITION BY toYYYYMMDD(publish_date) ORDER BY(id, city, region, name)
AS SELECT id, city, region, name, publish_date FROM study.house WHERE publish_date > toDate('2022-10-01');
// 插入数据
INSERT INTO study.house VALUES (2, '上海', '静安', '彭一小区', 70000, toDateTime('2022-05-06'));
INSERT INTO study.house VALUES (2, '上海', '静安', '彭一小区', 70000, toDateTime('2022-10-06'));
TRUNCATE TABLE study.house;
SELECT * FROM study.house_new_mv;