查询与过滤 — 三值逻辑与条件的顺序
一句话总结
SQL的WHERE只通过真值的行,如果NULL混在一起,结果既不是真也不是假,而是未知,所以在使用条件时,一定要牢记第三个值。
为什么需要这个?
大多数编程语言只处理真和假两个值。SQL处理三个值。真、假和未知。NULL参与的所有比较都变成未知,WHERE只通过真行的值,所以未知像假一样被处理。
这个差异在实际工作中会造成一个安静的错误。例如,当条件被颠倒时,行数之和与总和不符的现象就是一个典型的例子。
SELECT count(*) FROM customers WHERE city = '서울'; -- 48
SELECT count(*) FROM customers WHERE city <> '서울'; -- 335
-- 합이 383 인데 전체는 400 이다. 나머지 17 은 city 가 NULL 인 행이다.
<>因为罗也无法过滤,所以NULL行在双方任何地方都没有。这时需要的是IS DISTINCT FROM是的。这个运算符将NULL与一个值进行比较,所以在上述例子中返回352。
怎么行动
整理经常使用的条件的性格的话是这样的。
| 条件 | 意义 | 注意事项 |
|---|---|---|
BETWEEN a AND b |
a 以上 b 以下 | 包括两端值。 如果在日期范围内使用,可能会遗漏最后一天的午夜之后。 |
IN (...) |
列表中之一 | 列表中有NULLNOT IN使用的话结果会全部消失 |
LIKE 'kim%' |
前缀一致 | 可搜索索引 |
LIKE '%kim%' |
部分匹配 | 因为不知道起始点,所以无法用普通索引进行搜索 |
IS NULL |
没有价格 | = NULL银总是0行 |
COALESCE(a, b) |
如果a为NULL,则用作b | 表示用替换,如果用作条件,则无法访问索引。 |
CASE从上面开始选择第一个符合条件的项目。因此,列出重叠条件时,顺序即优先顺序。这是因为在划分金额区间时,从较大的值开始使用是惯例的原因。
也需要指出页码。ORDER BY没有LIMIT不能保证只要输入就会出现什么行。而且如果排序标准有平分,那么在页面之间会出现行重复或遗漏。**排序必须始终包括唯一值,并进行tie-break。**在实际工作中ORDER BY created_at DESC, id DESC最后像这样附加基本键。
在现场相遇的样子
OFFSET因为方式的页码翻页随着后面的页面越多就越慢。OFFSET 10000是读完最后一行后丢弃的。替代方案是以最后看到的值为基准继续读取的游标方式。条件是WHERE (created_at, id) < (마지막값, 마지막id)变成形状后,通过索引搜索直接找到开始点。
NULL 创造的三个值逻辑
SQL的比较不是真·假,而是真·假·不知道。这就是条件句的运行。 换。
NULL = NULL → UNKNOWN (참이 아니다)
NULL <> 1 → UNKNOWN
NULL IS NULL → TRUE ← 이것만 참이 된다
WHERE只留下真善美。UNKNOWN像谎言一样被抛弃。所以这样的
发生事情了。
-- status 가 NULL 인 행은 두 질의 어디에도 안 나온다
select * from orders where status = 'done';
select * from orders where status <> 'done';
要处理整个内容,必须指定NULL。
where status is distinct from 'done' -- NULL 도 "다르다" 로 본다
where status <> 'done' or status is null
where coalesce(status, '') <> 'done'
IS DISTINCT FROM这个是最干净的。将NULL比作一个值。
统计上也不同。count(*)虽然只算行count(col)只有不是NULL的
接受。avg·sum也忽略NULL,如果要将缺失视为0的话coalesce
必须填写。
条件的顺序(一般)不会改变性能。
WHERE a = 1 AND b = 2即使在更改顺序,优化器也会自行决定。人
要关注的不是顺序,而是可以使用索引的形式。
-- ❌ 인덱스를 못 쓴다 — 컬럼에 함수를 씌웠다
where date(created_at) = '2026-09-06'
where upper(email) = 'A@B.COM'
-- ✅ 범위로 바꾸거나 표현식 인덱스를 만든다
where created_at >= '2026-09-06' and created_at < '2026-09-07'
create index on users ((upper(email)));
LIKE也是如此。'abc%'虽然使用索引'%abc'不能写。
如果需要从后面查找的话,请写trigram索引或专业搜索。
至少阅读执行计划
explain (analyze, buffers) select …;
analyze实际上反过来看,buffers显示了读了多少。要看的
是三个。
- Seq Scan vs Index Scan — 大表格中如果出现Seq Scan,就怀疑索引。但是 表格越小,Seq Scan就越快。
- rows=估计和actual rows — 如果有很大的差异,统计数据就过时了(
ANALYZE). - Buffers: shared read — 从磁盘读取的量。
hit如果这个多的话,卡西会听得很好。 是。
下次实习要做的事情
在实际的电商模式中,依次使用BETWEEN、IN、LIKE、COALESCE、CASE、IS DISTINCT FROM。特别是在混合了NULL的列中,当反转条件时,会亲自体验行数不符的经历。