在 SQLite 中,INDEXED BY 是 DELETE、UPDATE、SELECT 语句中的一个 高级特性,用于 强制指定 查询或修改操作使用(或不使用)某个特定索引。
主要用于 性能调优 或 绕过优化器选择错误的索引。
一、基本语法
[DELETE | UPDATE | SELECT] ...
INDEXED BY 索引名
...
或 禁止使用索引:
INDEXED BY (无索引名称) -- 写成空名称
二、三种用法
| 写法 | 含义 |
|---|---|
INDEXED BY idx_name | 强制使用 名为 idx_name 的索引 |
INDEXED BY ( ) 或 INDEXED BY '' | 强制不使用任何索引(全表扫描) |
不写 INDEXED BY | 由 查询优化器自动选择 索引 |
三、实际示例
示例表结构
CREATE TABLE users (
id INTEGER PRIMARY KEY,
email TEXT,
status TEXT,
created_at DATETIME
);
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_users_status ON users(status);
1. 强制使用指定索引
SELECT * FROM users
INDEXED BY idx_users_email
WHERE email = 'alice@example.com';
即使优化器认为
idx_users_status更优,也强制走idx_users_email
2. 强制全表扫描(禁止索引)
SELECT * FROM users
INDEXED BY ( )
WHERE status = 'active';
即使有
idx_users_status索引,也不使用,强制全表扫描
适用于:调试、测试索引效果、避免索引缺陷
3. UPDATE / DELETE 中使用
-- 强制用 email 索引更新
UPDATE users
INDEXED BY idx_users_email
SET status = 'inactive'
WHERE email = 'bob@example.com';
-- 强制不使用索引删除
DELETE FROM users
INDEXED BY ( )
WHERE status = 'deleted';
四、查看执行计划(验证是否生效)
EXPLAIN QUERY PLAN
SELECT * FROM users INDEXED BY idx_users_email WHERE email = 'x';
输出示例:
SEARCH TABLE users USING INDEX idx_users_email (email=?)
→ 成功强制使用!
五、什么时候用 INDEXED BY?
| 场景 | 推荐使用 |
|---|---|
| 优化器选错索引(导致慢查询) | ✅ |
| 调试:对比有无索引性能 | ✅ |
| 临时绕过损坏/低效索引 | ✅ |
| 日常查询 | ❌ 应信任优化器 |
警告:滥用
INDEXED BY会让 SQL 不可移植,维护成本高!
六、常见错误
-- 错误:索引名拼错
SELECT * FROM users INDEXED BY idx_wrong_name WHERE email = 'x';
-- → 报错:no such index: idx_wrong_name
-- 正确:先确认索引存在
PRAGMA index_list(users);
七、替代方案(推荐)
| 目标 | 推荐做法 |
|---|---|
| 提升性能 | 创建合适索引 + ANALYZE |
| 强制索引 | 仅调试时用 INDEXED BY |
| 避免索引 | 临时测试用 INDEXED BY () |
总结:INDEXED BY 使用建议
| 用法 | 是否推荐 | 说明 |
|---|---|---|
INDEXED BY idx_name | ⚠️ 仅调试 | 强制走指定索引 |
INDEXED BY () | ⚠️ 仅测试 | 强制全表扫描 |
| 不写(默认) | ✅ 推荐 | 信任优化器 |
最佳实践:
-- 1. 先用 EXPLAIN QUERY PLAN 分析
EXPLAIN QUERY PLAN SELECT ...;
-- 2. 若优化器选错,才考虑临时加:
SELECT ... INDEXED BY idx_correct_one;
-- 3. 长期解决:调整索引设计 + ANALYZE
ANALYZE;
需要我帮你 分析一个慢查询 并判断是否需要 INDEXED BY?
把 SQL 和 EXPLAIN QUERY PLAN 结果发我!