必须写成WHERE (flags & 4) != 0或= 4,因&优先级低于=,不加括号会导致语义错误;字段须为TINYINT UNSIGNED NOT NULL;高频查询应建生成列+索引;视图中需用CASE解包而非裸写位运算。

WHERE (flags & mask) != 0 是基本写法,不是 WHERE flags & mask
不加括号或用错等号,查询会静默出错。MySQL、SQL Server、PostgreSQL 中 & 的优先级低于 =,所以 WHERE flags & 4 = 4 实际被解析为 WHERE flags & (4 = 4) → WHERE flags & 1,永远只查第 0 位。必须写成:WHERE (flags & 4) != 0(查“含该位”)或 WHERE (flags & 4) = 4(查“该位必须为 1,其他位不限”)。
常见错误还包括:WHERE flags & (1 OR 2)——OR 是逻辑运算符,不是位或;应写 WHERE (flags & 3) != 0 表示“至少含 bit0 或 bit1”。
字段类型必须是无符号整型,且 NOT NULL
用 TINYINT UNSIGNED 存 ≤8 个标签,SMALLINT UNSIGNED 存 ≤16 个,别用 INT SIGNED——负数无业务意义,还浪费一位。一旦字段允许 NULL,WHERE (flags & 4) != 0 在遇到 NULL 行时结果为 UNKNOWN,该行被过滤掉,但你根本不会报错,只会“少查数据”。务必定义为:flags TINYINT UNSIGNED NOT NULL DEFAULT 0。
索引对位运算条件效果有限,高频单比特查询要建生成列
给 flags 字段加普通 B+Tree 索引,对 WHERE flags = ? 或 WHERE flags IN (?, ?, ?) 有效,但对 WHERE (flags & 8) = 8 基本不走索引,大概率全表扫描。
如果某一位(比如是否 VIP)被高频查询,正确做法是:
• MySQL 5.7+:ALTER TABLE users ADD COLUMN is_vip TINYINT AS ((flags & 8) = 8) STORED,再 CREATE INDEX idx_is_vip ON users(is_vip);
• 注意 STORED 关键字不能漏,否则无法索引;
• SQL Server 可用计算列 + 索引;PostgreSQL 可建函数索引 CREATE INDEX ON users ((flags & 8)),但 MySQL 不支持。
应用层必须用常量代替裸数字,SQL 中避免硬编码
代码里写 WHERE flags & 12,半年后没人知道 12 是哪几个标签组合。应在应用中定义:READ = 1, WRITE = 2, DELETE = 4, ADMIN = 8,组合用 READ | WRITE 计算出 3;SQL 中传参时也应传预计算值,如 WHERE (flags & ?) = ?,参数填 3 和 3。
数据库视图中不要裸露 status & 4 = 4,改用:CASE WHEN (status & 4) = 4 THEN 1 ELSE 0 END AS is_locked,下游可读可索引(若该列物理化并建索引)。

















