yii框架本身不创建数据库索引,索引由数据库引擎管理;yii仅通过migration工具安全、可追溯地执行create index语句,确保版本控制与回滚能力。

Yii 框架本身不创建数据库索引,索引必须由数据库引擎管理;Yii 只提供迁移(migrate)工具帮你安全、可追溯地执行 CREATE INDEX 语句。
用 migration 创建 MySQL/PostgreSQL 索引
这是最规范、推荐的方式,尤其在团队协作或生产环境部署时。迁移文件确保索引变更可版本控制、可回滚。
-
yii migrate/create add_index_on_user_email生成空迁移文件 - 在
up()中调用$this->createIndex('idx_user_email', '{{%user}}', 'email') - 若需唯一索引,第四个参数传
true:$this->createIndex('idx_user_email_unique', '{{%user}}', 'email', true) - 复合索引字段顺序很重要:例如查询常带
status和created_at,应写成['status', 'created_at'],而非反过来——否则WHERE status = ?能命中,而WHERE created_at > ?不能 - 别在迁移里硬编码表名,始终用
{{%user}}这种引用语法,适配不同表前缀
ActiveRecord rules 里的 unique 不等于建索引
很多人误以为在模型 rules() 里写 ['email', 'unique'] 就会自动建索引——它只加应用层校验,**不会触达数据库**。没索引时,这个验证会全表扫描,数据量一过万就明显变慢。
- 要真正加速
unique校验,必须手动在数据库加唯一索引(用 migration 或 SQL) - 同理,
exists、in等验证器也不自动建索引 - 验证器报错信息如
"Email has already been taken"是查出来的,但查的过程是否高效,取决于你有没有给email字段建索引
Query Builder 和 ActiveRecord 查询是否走索引?关键看 SQL,不是看 Yii 写法
Yii 生成的 SQL 能否命中索引,和你是用 User::find()->where(['email' => $e])->one() 还是 (new Query())->from('user')->where(['email' => $e])->one() 完全无关。决定因素只有两个:
- WHERE 条件字段是否有对应索引(单列 or 复合,顺序是否匹配)
- 是否触发索引失效操作:比如对字段用函数
WHERE UPPER(email) = 'A@B.COM'、或模糊查询写成LIKE '%abc' - 避免
SELECT *:尤其当表有大字段(TEXT/BLOB)时,即使索引能用,网络和内存开销也大;用select(['id', 'name', 'email'])明确指定字段 - 注意隐式类型转换:比如
WHERE user_id = '123'(字符串)查 INT 字段,MySQL 可能放弃索引;统一用整型传参
索引不是越多越好,线上加索引要小心
MySQL 5.6+ 支持在线 DDL,但仍有风险。特别是大表,CREATE INDEX 仍可能锁表或拖慢写入。
- 加索引前先用
EXPLAIN SELECT ...确认当前慢在哪,别凭感觉加 - 不要为每个
WHERE字段单独建索引,优先考虑复合索引覆盖多个高频查询组合 - 删除无用索引:
SELECT * FROM sys.schema_unused_indexes;(MySQL 8.0+)或分析慢日志 +information_schema.STATISTICS - 测试环境务必用真实数据量压测,小表上加索引看不出效果,也看不出锁表现
最容易被忽略的一点:索引优化永远从慢查询开始,而不是从模型定义或迁移文件开始。先 SHOW CREATE TABLE 看现有结构,再 EXPLAIN 看执行计划,最后才动手加索引——否则你很可能在优化一个根本没被调用的查询路径。











