语句 · 2026 年 5 月 26 日 · 9 分钟
COUNT 和 COUNT DISTINCT 不是同一指标
COUNT(*) 数行,COUNT(col) 数非空,COUNT(DISTINCT col) 去重。口语里的「有多少」,常常没说清数的是哪一种。粒度笔记和这条是姐妹篇:先说一行是什么,再选 COUNT。
人数几乎总要去重
同一人多单,COUNT(*) 会当多人。
空值
COUNT(user_id) 会丢掉空。空是未登录还是脏数据,要先看。
近似去重要声明
超大表用近似算法时,在收据上写「近似」。不要装成精确。
一次完整的问法可以先写成下面这样:
3 月已支付:订单行数、去重用户数。
落到语句上,草稿常常是:
SELECT COUNT(*) AS order_cnt, COUNT(DISTINCT user_id) AS user_cnt
FROM orders
WHERE pay_time >= DATE '2026-03-01'
AND pay_time < DATE '2026-04-01'
AND pay_status = 'paid';
两个数并排。谁再把「有多少」说成一个词,就让他看这一行。
语句是收据,默认只读
第一纪律是 SELECT。草稿里出现更新、删除、结构变更,整张收据作废。第二纪律是时间窗。大表没有时间条件,不跑。第三纪律是粒度。GROUP BY 的键必须和问题里的维度一一对应。
一对多关联会把头上的金额按明细复制,看起来像增长,其实是扇形。COUNT 和 COUNT DISTINCT 不是同一指标。NULL 不是 0。日期函数没有世界语,能写绝对区间就写绝对区间。
复杂逻辑用公共表表达式拆开。拆开是为了给人看中间结果。先对再快。用索引去救一条口径错误的语句,会把错误生产化。
读完这一辑可以做什么
把你最近一条问数语句拆成三段 WITH:过滤、聚合、排名。每一段单独跑。有一段解释不清,就回到提问,不要在语句里继续加花样。
有多少人、多少单、多少行,三个 COUNT 必须并排出现。