行构造器比较
行构造器把多个列当作一个元组参与比较:WHERE (city, status) IN (('Beijing', 1), ('Shanghai', 2)) 比一串 OR 更短、更不容易写错括号。MySQL 与 PostgreSQL 都支持,(a, b) = (1, 2) 这种等值比较也属于同一族语法。
基本信息
| 等价改写 | (a,b) IN ((1,2),(3,4)) 即 (a=1 AND b=2) OR (a=3 AND b=4) |
|---|---|
| 比较规则 | 按从左到右逐列比较 |
| 元素个数 | 每行元素个数必须与左侧列数一致 |
| 索引影响 | 部分版本下行比较的索引利用弱于展开写法 |
| 适用平台 | MySQL 与 PostgreSQL 均支持 |
典型使用场景
- 按「城市加状态」这类多列组合批量筛选
- 把冗长的 OR 链改写成更易读的形式
- 按复合主键批量查询
- 对比改写前后的执行计划差异
- 用简单元组比较做业务规则的二次校验
示例
示例
-- 多列组合命中:比 OR 链更短
SELECT * FROM t
WHERE (city, status) IN (('Beijing', 1), ('Shanghai', 2));
-- 等值比较
SELECT * FROM t WHERE (a, b) = (1, 2);
-- 与展开写法等价,改写后可用 EXPLAIN 对比
SELECT * FROM t
WHERE (city = 'Beijing' AND status = 1)
OR (city = 'Shanghai' AND status = 2);常见用法
| 写法 | 含义 | 注意 |
|---|---|---|
| (a, b) = (1, 2) | 两列分别相等 | 元素个数必须对齐 |
| (a, b) IN ((1,2),(3,4)) | 命中任一组合 | 等价于 AND/OR 展开 |
| (a, b) > (1, 2) | 逐列字典序比较 | 语义不直观,慎用 |
| (a, b) IS NULL | 判断整体是否为 NULL | 与逐列 IS NULL 语义不同 |
行比较的索引利用不如展开写法稳定:部分版本上优化器无法把它拆成两次索引范围扫描。重要查询改写后用 EXPLAIN 对比,别只看语句更短。
候选组合很多时(上百条)建议改用临时表连接或批量接口:超长 IN 列表既难维护,也会给优化器带来额外负担。
行构造器也能和子查询配合,例如 (a, b) IN (SELECT x, y FROM t),写法简洁但同样要确认列数与类型一致,否则报错信息不太直观。
批量接口里用它传多组键值很常见:此时要注意列表长度,几百组以上时改用临时表连接或分批查询,索引利用与可读性都会更好。