bigint 字段加索引会不会拖慢写入?
会,但通常不明显——
BIGINT是固定 8 字节长度,B+ 树索引的比较和存储开销稳定,远小于
TEXT或长
VARCHAR。真正影响写入性能的是索引数量、是否频繁更新该字段、以及是否在高并发 INSERT/UPDATE 场景下触发页分裂。
常见误判点:有人看到
INSERT变慢就怀疑
BIGINT索引本身重,其实更可能是没用好主键或二级索引顺序。比如在自增
id BIGINT PRIMARY KEY后,再对另一个
user_id BIGINT建单独索引,若查询常带
WHERE user_id = ? AND status = ?,那单列
user_id索引效率反而不如联合索引
(user_id, status)。 高频写入表慎用多个单列
BIGINT索引,优先合并为复合索引 如果该
BIGINT字段极少被
WHERE或
JOIN使用,加索引纯属冗余
ALTER TABLE ADD INDEX期间会锁表(5.6+ 支持
ALGORITHM=INPLACE,但仍需元数据锁)
什么时候必须用 bigint 而不是 int?
不是“想存大数就用
BIGINT”,而是看业务增长预期。MySQL 的
INT有符号上限是 2147483647(约 21 亿),一旦主键或计数器接近这个量级,就会报
ERROR 1062 (23000): Duplicate entry '2147483647' for key 'PRIMARY'或直接溢出变负数。
典型场景:
订单号、流水号采用时间戳 + 自增拼接,64 位时间戳已占 ~10 位数字,再叠加序列很容易超INT范围 社交类应用的粉丝数、互动数,头部用户可能达数十亿次操作 分库分表后全局唯一 ID(如雪花算法生成的 64 位整数)必须用
BIGINT UNSIGNED
注意:
BIGINT占用更多内存和磁盘空间,InnoDB 的主键会作为聚簇索引,所有二级索引叶子节点都包含主键值——所以主键用
BIGINT会让所有二级索引变大。
create index 时要不要指定长度?
不需要,也不能。MySQL 不支持对整数类型(包括
TINYINT、
INT、
BIGINT)指定前缀长度,像
CREATE INDEX idx_uid ON t (user_id(10))这种写法会直接报错:
ERROR 1089 (HY000): Incorrect prefix key; the used key part isn't a string。
只有字符串类型(
CHAR、
VARCHAR、
TEXT)才允许用括号指定前缀,例如
INDEX (title(100))。对
BIGINT加索引就是全字段参与排序和查找,没有“截断”概念。
顺带提醒:如果字段定义为
BIGINT UNSIGNED,索引自动按无符号处理;但如果查询里写成
WHERE user_id = -123,MySQL 会隐式转成无符号值(变成极大正数),导致索引失效且查不到数据。
explain 显示 type=range 但实际很慢?检查这几个点
当
EXPLAIN中
type是
range,说明用了
BIGINT索引做范围扫描(如
WHERE id BETWEEN 1000 AND 2000),但响应仍慢,大概率不是索引本身问题,而是: 扫描行数太多:
rows列显示预估扫描 50 万行?哪怕每行只要 0.1ms,也得 50 秒 —— 这时候应考虑加过滤条件或改用覆盖索引 回表代价高:如果
SELECT *且二级索引不包含所有需要字段,InnoDB 得根据主键反复回聚簇索引取数据,随机 IO 拉垮性能 统计信息过期:
ANALYZE TABLE没跑过,优化器误判了选择性,可能本该走其他索引却选了这个
BIGINT字段的索引 隐式类型转换:
WHERE user_id = '12345'(字符串)会导致索引失效,
type降级为
ALL,但有时因字符集或 collation 问题表现诡异,务必用
SHOW WARNINGS看真实执行计划
最稳妥的做法:用
SELECT ... FROM t WHERE user_id = ?测试单值等值查询是否走索引,确认基础有效性后再拓展到范围或组合条件。
