CodeIgniter 4 中必须用 Migration 创建索引:在 up() 中用 forge->add_key() 或 forge->add_index() 定义,down() 中对应删除;add_index(['col1','col2'], 'name') 建联合索引,加 true 参数为唯一索引;CI4.4+ 支持链式调用,旧版需分步操作。

CodeIgniter 4 中怎么用 Migration 创建数据库索引
Migration 是 CI4 唯一推荐的索引创建方式,直接写 SQL 或手动进数据库加索引,后续部署、协作、回滚都会出问题。
关键点:索引必须在 up() 里定义,用 forge->add_key() 或 forge->add_index();down() 里必须对应删除,否则迁移失败。
-
add_key('column_name', 'index_name')用于主键/外键(会自动加PRIMARY或FOREIGN类型) -
add_index(['col1', 'col2'], 'idx_col1_col2')才是普通联合索引的正确定义方式 - 别漏掉第三个参数
true——add_index(['status'], 'idx_status', true)表示唯一索引,不加就是普通索引 - CI4.4+ 支持
forge->create_table()后链式调用->add_index(),但老版本必须分两步:先create_table(),再单独add_index()
CodeIgniter 3 没有 Migration 怎么安全加索引
CI3 不带原生迁移,硬写 SQL 很容易在不同环境(开发/测试/生产)漏加或加错。最稳妥的做法是封装成可重复执行的“索引检查脚本”。
核心逻辑:查 INFORMATION_SCHEMA.STATISTICS 确认索引是否存在,不存在才建。不能靠 try-catch 捕获 SQLSTATE[HY000]: General error: 1061 Duplicate key name 来兜底——这说明已经出过一次错了。
- 用
$this->db->query("SHOW INDEX FROM `users` WHERE Key_name = 'idx_email'")更轻量,兼容性比查INFORMATION_SCHEMA好 - 建索引语句必须用
ALTER TABLE `users` ADD INDEX idx_email (`email`),别写成CREATE INDEX—— MySQL 5.7- 有些版本不支持后者对已有表操作 - 如果字段类型是
TEXT或VARCHAR(255),必须指定前缀长度:ADD INDEX idx_title (title(191)),否则在 utf8mb4 下直接报错
为什么 $this->db->query() 执行 CREATE INDEX 失败却没报错
常见现象:代码里写了 $this->db->query('CREATE INDEX idx_name ON table(col)');,执行完无报错,但查数据库发现索引根本没建。根本原因是 CI3/CI4 的 query() 默认不抛异常,错误被静默吞掉了。
- CI4 必须显式开启:在
app/Config/Database.php的数据库配置里加上'DBDebug' => true - CI3 要改
system/database/DB_driver.php,把log_errors设为true,或临时加var_dump($this->db->error());看真实错误 - 更大概率是权限问题:
CREATE INDEX需要INDEX权限,很多线上库只给SELECT,INSERT,UPDATE,DELETE,这时候必须找 DBA 开权限,而不是换写法
联合索引顺序写反了会导致查询不走索引
比如 WHERE 条件是 WHERE status = 1 AND category_id = 5,但你建的是 INDEX idx_cat_status (category_id, status) —— MySQL 可能只用上 category_id,status 变成过滤而非索引查找。
这不是 CodeIgniter 的问题,但用 CI 封装时容易忽略底层规则。建索引前先看慢查询里的 WHERE 和 ORDER BY 字段顺序。
- 等值查询字段放前面,范围查询(
>,BETWEEN)放后面 - 如果经常
ORDER BY created_at DESC,且和WHERE status = ?一起用,索引应为(status, created_at),不是反过来 - 用
EXPLAIN SELECT ...验证key_len和rows,别只看key显示了就以为生效了
索引不是建了就完事,尤其是涉及时间字段、JSON 列、全文搜索的场景,MySQL 版本差异、字符集、统计信息过期都会让执行计划突然失效。上线前至少拿生产数据量级的副本跑一遍 EXPLAIN。









