mysql如何为bigint类型字段创建索引_mysql字段类型与索引优化

来源:这里教程网 时间:2026-02-28 20:48:04 作者:

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 = ?
测试单值等值查询是否走索引,确认基础有效性后再拓展到范围或组合条件。

相关推荐