必须写成(column & mask) = mask,因&优先级低于=,否则解析为column & (mask = mask)导致逻辑错误;各数据库语法差异大,且位运算无法走索引,需冗余生成列并建索引优化。

直接用 & 做掩码判断必须写成 (column & mask) = mask,否则因运算符优先级错误导致全表误匹配或漏数据——这是最常踩、也最隐蔽的坑。
MySQL里查“有某权限”为什么总查不准?
因为 & 的优先级低于 =,不加括号就会被错误解析。比如写 permissions & 4 = 4,实际执行的是 permissions & (4 = 4) → permissions & 1,永远只检查最低位。
- 正确写法只有:
(permissions & 4) = 4(查第3位是否为1) - 查“同时有读(1)和写(2)”:用
(permissions & 3) = 3,不是permissions & 1 AND permissions & 2 - 查“没有删除权限(4)”:用
(permissions & 4) = 0,别用!= 4(会漏掉其他位组合为4的情况) -
NULL & 4结果仍是NULL,整行不命中——这不是bug,而是语义上“权限未知”,需提前WHERE permissions IS NOT NULL过滤
PostgreSQL / SQL Server / Oracle / SQLite 怎么写才兼容?
语法表面相似,但底层支持差异大,硬套 MySQL 写法大概率报错。
- PostgreSQL 和 SQL Server:支持
&,写法和 MySQL 完全一致,但字段必须是整型(TEXT会报错) - Oracle:必须用
BITAND(permissions, 4) = 4,写permissions & 4直接抛ORA-00920 - SQLite:默认把
&当字符串连接符;3.35+ 才支持bitand(permissions, 4) = 4,旧版本得靠自定义函数或改 schema - 所有数据库都认十进制常量(如
4),别用0x4或0b100(多数不支持)
为什么加了索引还是慢?怎么救?
WHERE (permissions & 4) = 4 几乎无法走 B+Tree 索引——优化器没法反推位运算条件到索引范围,结果就是全表扫描。
- 千万级表别硬扛,必须冗余生成列:
ALTER TABLE users ADD has_delete TINYINT AS ((permissions & 4) = 4) STORED - 再建索引:
CREATE INDEX idx_has_delete ON users(has_delete)(注意STORED关键字不能漏) - 查询改写为:
WHERE has_delete = 1,就能稳定命中索引 - 字段类型必须是整型(
TINYINT、INT),VARCHAR会静默转成0,查出来永远空
真正容易被忽略的点是:位运算本身很快,但一旦脱离整型字段、括号、生成列这三要素中的任何一个,就从“高效”变成“静默失效”。线上出问题时,往往不是性能差,而是逻辑错得悄无声息。











