优先用 % 运算符:mysql、postgresql、sql server、oracle、sqlite 均支持,语法紧凑;mod() 仅 mysql/mariadb 和 oracle 原生支持,sql server 不识别,postgresql 要求小写且类型严格,sqlite 中仅为 % 别名。

MOD 不是通用 SQL 运算符,直接写 MOD(id, 2) = 1 在 PostgreSQL、SQL Server、SQLite 等多数数据库里会报错,只有 MySQL/MariaDB 和 Oracle 原生支持;真正跨库可用的是 % 运算符。
WHERE 中用 % 还是 MOD()?
优先用 %:它在所有主流数据库(MySQL、PostgreSQL、SQL Server、Oracle、SQLite)中都有效,且语法更紧凑。MOD() 虽是 SQL 标准函数,但实际支持度有限——PostgreSQL 要求小写 mod() 且类型严格匹配,SQL Server 根本不认,SQLite 的 MOD() 只是 % 的别名。
常见错误:
- 把 MySQL 脚本直接复制到 pgAdmin 执行 → 报错
function mod does not exist - 在 SQL Server Management Studio 里写
SELECT MOD(id, 5)→ 语法错误提示'MOD' is not a recognized built-in function name - 参数顺序写反:
MOD(2, id)是错的,必须是MOD(id, 2)或id % 2
id % 2 = 1 为什么可能漏掉负奇数?
因为不同数据库对负数取模的符号处理不一致:
- MySQL:
-3 % 2返回-1,所以id % 2 = 1不匹配负奇数 - PostgreSQL / Oracle:
-3 % 2返回1,判断正常
更安全的写法是:id % 2 != 0 —— 它对正负奇数都成立,且兼容所有引擎。如果字段允许 NULL,注意 NULL % 2 != 0 结果为 UNKNOWN,整行会被过滤,无需额外补 OR id IS NULL,除非业务真要包含空值。
按查询结果“第几行”奇偶筛选,不能直接对 id 取模
写 WHERE id % 2 = 1 筛的是 id 值为奇数的记录,不是结果集的第 1、3、5 行。真要按输出顺序取奇数行,必须先生成行号:
- MySQL 8.0+ / PostgreSQL / SQL Server / Oracle:用
ROW_NUMBER() OVER (ORDER BY ...) - 必须套子查询或 CTE,不能在
WHERE直接引用窗口函数 - 示例:
SELECT * FROM ( SELECT *, ROW_NUMBER() OVER (ORDER BY id) AS rn FROM users ) t WHERE t.rn % 2 = 1;
没写 ORDER BY 时,ROW_NUMBER() 行为未定义,结果不可靠。
id % 2 = 1 能走索引吗?
不能。B-tree 索引无法加速 id % 2 = 1 这类表达式计算,因为索引存储的是原始 id 值,不是余数值。全表扫描几乎不可避免。
高频奇偶筛选的替代方案:
- 加持久化计算列(MySQL 5.7+):
is_odd TINYINT AS (id % 2) STORED,再建索引 - 业务层冗余字段:
id_is_odd,写入时同步设置 - 接受扫描——除非是核心路径,否则为这点优化加额外维护成本不划算
真正容易被忽略的是:% 看似简单,但它把字段拖进表达式后,就彻底告别索引了;而很多人直到慢查询告警才意识到这点。











