首页/数据/NoSQL 速查/SELECT 查询基础
ClickHouse56 条

SELECT 查询基础

SELECT 按列式读取、只扫描用到的列:支持表达式、别名、WHERE/GROUP BY/HAVING/ORDER BY/LIMIT 与丰富的内置函数,聚合与窗口计算是大数据量下的常见用法。

NoSQL 速查数据更新于 2026-10-13

SELECT 是什么

ClickHouse 的 SELECT 是列式查询:只扫描用到的列,配合稀疏索引与分区裁剪,能在海量数据上做秒级聚合。语法与标准 SQL 接近,支持表达式、别名、WHERE、GROUP BY、HAVING、ORDER BY、LIMIT,并提供 LIMIT BY、WITH TOTALS、WINDOW 等扩展能力。大数据量下的典型用法是聚合与窗口计算,而不是逐行取明细。

基本信息

基本结构SELECT expr [[AS] alias] FROM table [WHERE] [GROUP BY] [HAVING] [ORDER BY] [LIMIT]
常用聚合count()、sum、avg、min、max、uniq、quantile
特色能力LIMIT BY 分组取前 N、WITH TOTALS、WINDOW 子句
裁剪依赖分区键与排序键决定扫描范围
类型系统强类型,聚合结果类型按输入推断
适用版本ClickHouse 22.x 及以上语法稳定

典型使用场景

  • 按维度聚合统计,替代预计算的报表表
  • 按时间范围做趋势分析,配合 toDate 与 toStartOfHour
  • 明细抽样排查:加 LIMIT 快速看样本数据
  • 去重计数:uniq 与 uniqExact 权衡精度与性能
  • 分组取前 N 条:用 LIMIT BY 替代窗口函数
  • 与外部 BI 对接:直接输出宽表结果集

示例

示例
SELECT
    toDate(ts) AS d,
    count() AS requests,
    round(avg(value), 2) AS avg_value,
    uniq(user_id) AS users
FROM metrics
WHERE ts >= now() - INTERVAL 7 DAY          -- 范围条件才能裁剪分区与索引
GROUP BY d
HAVING requests > 100
ORDER BY d
LIMIT 100;

常用聚合与函数

函数作用注意点
count()行数统计不带参数最快
sum / avg求和与均值数值类型才可用
min / max取极值常用于时间区间
uniq近似去重计数误差极小但非精确
uniqExact精确去重计数内存占用更高
quantile分位数如 quantile(0.95)(dur)

查询与裁剪要点

  • 对分区键用范围条件,避免函数包装导致无法裁剪
  • 排序键前缀上的条件裁剪效果最好
  • SELECT 只写需要的列,列式存储下能显著减少 IO
  • PREWHERE 比 WHERE 更早过滤,适合高选择性的条件
  • GROUP BY 后的 ORDER BY 要配合 LIMIT,避免无界排序
  • 大结果集导出用 LIMIT 分批,避免一次性拉满内存

结果判读与常见偏差

  • uniq 是近似去重,结果与 uniqExact 可能有极小差异
  • avg 忽略 NULL,分母与业务口径要提前确认
  • count() 与 countDistinct 的语义不同,别混用
  • 时区影响 toDate 结果,跨时区业务要显式指定
  • 浮点求和存在精度误差,金额类应存整数分
  • HAVING 在分组后过滤,条件写成 WHERE 才能真正减少扫描量
ClickHouse 不允许在 SELECT 里使用未参与 GROUP BY 的裸列(除 any、argMax 等聚合包裹外),分组口径必须写清楚。
对分区键做函数包装(如 toYYYYMM(ts) 直接等于某个值)会失去裁剪能力,尽量改写成范围条件,把函数留在分区表达式里。
ORDER BY 没有 LIMIT 的大排序会消耗大量内存,超过内存限制才落盘,报表查询务必带 LIMIT 或先聚合降维。
读明细与读聚合要分开设计:明细查询靠 LIMIT 与主键条件,统计分析靠预聚合物化视图,混在一张表上很容易两头都不快。

查询性能实践

  • 只选需要的列,列式存储按列读取,减少 IO 最直接
  • 过滤条件尽量前置,放在 PREWHERE 或 WHERE 的靠前位置
  • 大表统计先靠分区裁剪,再靠排序键裁剪
  • GROUP BY 键基数过高时会占用大量内存,考虑预聚合
  • 用 EXPLAIN 看读取的 granule 与行数,判断裁剪是否生效
  • 结果集大时用 LIMIT 分批导出,避免一次性拉满内存

常见口径差异

  • count() 统计行数,countDistinct 统计去重值,语义完全不同
  • uniq 是近似去重,与 uniqExact 结果可能有极小差异
  • avg 忽略 NULL,分母口径要与业务确认
  • toDate 受时区影响,跨时区业务要显式指定
  • 整型相除会截断,需要小数结果要转成浮点再算
  • 浮点求和存在精度误差,金额类建议按分存整数
LIMIT 在聚合之后执行,不会减少扫描量;想真正减少读取,要靠分区与排序键裁剪,或用 PREWHERE 提前过滤。

易错点

  • 对分区键做函数包装可能失去裁剪,尽量改成范围条件
  • ORDER BY 无 LIMIT 的大排序会消耗大量内存,超过阈值才落盘,查询会明显变慢
  • SELECT 里写未参与 GROUP BY 的裸列会直接报错,需要 any 或 argMax 包裹
  • uniq 是近似去重,对精确性要求高的场景应改用 uniqExact
  • 把过滤条件写在 HAVING 里而不是 WHERE,扫描量不会减少,性能与业务口径都会受影响

数据来源与参考

  • ClickHouse Docs: SELECT
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌