ceil(-2.1) 等于 -2,因为 ceil 返回 ≥ 当前值的最小整数,-2.1 右侧最近的整数是 -2;floor(-2.1) = -3,因它返回 ≤ 当前值的最大整数。

CEIL(-2.1) 为什么等于 -2?负数取整方向必须按数轴理解
CEIL 不是“进一”,而是返回 ≥ 当前值的最小整数;FLOOR 不是“舍去小数”,而是返回 ≤ 当前值的最大整数。负数时,直觉容易错:-2.1 的右侧(更大)是 -2,左侧(更小)是 -3,所以 CEIL(-2.1) = -2,FLOOR(-2.1) = -3。
常见错误包括把 CEIL(-2.1) 写成 -3,或在分页、计费逻辑中误用导致少算单位。测试时务必覆盖负数用例:SELECT CEIL(-2.1), FLOOR(-2.1) —— 结果必须是 -2 和 -3。
FLOOR(price / 50) * 50 这种写法为什么比 CEIL 配减法更稳?
区间分组(如价格每 50 元一段)本质是向下对齐左边界,FLOOR(price / 50) * 50 直接给出 0、50、100… 这类起始点,逻辑清晰且无边界歧义。而用 CEIL(price / 50) * 50 - 50 在 price 恰好为 50 的倍数时会出错(比如 price=50 → CEIL(1)*50-50 = 0),导致归类偏移。
实操建议:
- 字段含
NULL时先COALESCE(price, 0),否则整个表达式结果为NULL - 避免写成
ORDER BY FLOOR(x/10) * 10而不加括号——除法和乘法优先级相同,但语义上必须先除后乘 - 若 price 是字符串类型,必须先
CAST(price AS DECIMAL(12,4)),否则报错function ceil(text) does not exist
为什么对索引字段直接用 FLOOR/CEIL 可能让查询变慢?
FLOOR(price) 或 CEIL(price) 是函数调用,MySQL 无法直接利用 price 字段上的索引加速计算。即使原始字段有 B+Tree 索引,优化器也会退化为全表扫描或文件排序。
更严重的是类型隐式转换:输入是 DECIMAL(10,2),输出是 BIGINT,后续若写 WHERE FLOOR(price) = 10,MySQL 可能放弃使用索引,转而对每行计算后再比较。
替代方案:
- 等值判断改用范围:
WHERE price >= 10 AND price - 高频使用的取整结果,提前在应用层或物化视图里存为整型字段(如
price_floor_50) - 若必须 JOIN 或 GROUP BY 取整值,优先在子查询中完成计算,再外层操作
CEIL(COUNT(*) / @page_size) 分页总数计算的三个隐藏陷阱
表面看 CEIL(COUNT(*) / @page_size) 很自然,但实际有三处易漏:
- @page_size 是字符串或
NULL时,除法结果为NULL,CEIL(NULL)仍是NULL,总数丢失 - @page_size = 0 会触发
Division by zero错误,必须前置判断 - 高并发下每次执行都重算
COUNT(*)+CEIL,延迟高、压力大,不适合实时展示总页数
健壮写法示例:CEIL(COUNT(*) / CAST(COALESCE(@page_size, 10) AS DECIMAL(10,0))),并搭配缓存或近似统计(如 TABLE_ROWS)应对实时性要求低的场景。
真正复杂的地方不在语法,而在负数方向的理解是否牢固、索引是否被函数悄悄绕过、以及除法精度是否在跨版本 MySQL 中一致——这些点一旦出错,问题往往延迟暴露,排查成本远高于写时多加一行 CAST 或括号。











