SQLite 查询变慢时,先看 EXPLAIN QUERY PLAN 再动手加索引

举报
yd_268445051 发表于 2026/11/04 10:27:21 2026/11/04
【摘要】 查询从几毫秒变成几秒,第一反应往往是“加个索引”。但索引加错位置,不仅没用,还会拖慢写入。动手之前,先让 SQLite 自己说出它打算怎么执行这条 SQL:EXPLAIN QUERY PLAN。先复现慢查询假设有一张订单表,数据量上了十万级:CREATE TABLE orders ( id INTEGER PRIMARY KEY, user_id INTEGER NOT NULL...

查询从几毫秒变成几秒,第一反应往往是“加个索引”。但索引加错位置,不仅没用,还会拖慢写入。动手之前,先让 SQLite 自己说出它打算怎么执行这条 SQL:EXPLAIN QUERY PLAN。

先复现慢查询
假设有一张订单表,数据量上了十万级:

CREATE TABLE orders (
    id INTEGER PRIMARY KEY,
    user_id INTEGER NOT NULL,
    status TEXT NOT NULL,
    created_at TEXT NOT NULL,
    amount REAL NOT NULL
);

按用户查最近的已完成订单:

SELECT id, amount FROM orders
WHERE user_id = 42 AND status = 'paid'
ORDER BY created_at DESC LIMIT 20;

直接执行能出结果,但快慢看不出来。加上执行计划:

EXPLAIN QUERY PLAN
SELECT id, amount FROM orders
WHERE user_id = 42 AND status = 'paid'
ORDER BY created_at DESC LIMIT 20;

如果输出里出现 SCAN orders,说明 SQLite 在全表扫描:它把每一行都翻出来,再逐行判断条件。数据量越大,这一步越贵。理想的输出是 SEARCH orders USING INDEX,表示它直接通过索引定位到少量候选行。

索引的列顺序决定成败
给 user_id 单独加索引后,执行计划可能变成 SEARCH … USING INDEX idx_user (user_id=?),但这只是第一步:满足 user_id = 42 的行可能仍有上千条,SQLite 还要逐行过滤 status,再排序。
复合索引的列顺序要跟着查询走:等值条件在前,排序列紧随其后:

CREATE INDEX idx_orders_user_status_time
ON orders (user_id, status, created_at DESC);

这个索引的含义是:先按用户分组,再按状态分组,组内天然按时间倒序排列。查询时 SQLite 可以直接定位到 user_id = 42 AND status = ‘paid’ 这一段,取前 20 条即停,不用额外排序,也不用回表过滤大量无关行。改完之后再跑一次 EXPLAIN QUERY PLAN,确认出现 USING COVERING INDEX 或至少 SEARCH … USING INDEX,且没有 USE TEMP B-TREE FOR ORDER BY,才算改到位。

三个常见误区
第一,索引不是越多越好。每个索引都是一份额外的数据结构,写入、更新、删除时都要同步维护。给很少用于查询条件的列加索引,收益几乎为零,写入成本却实打实地增加了。
第二,函数和表达式会让索引失效。WHERE date(created_at) = ‘2026-11-04’ 无法直接用 created_at 上的普通索引,因为 SQLite 要先对每一行算出函数值再比较。改成范围条件 created_at >= ‘2026-11-04’ AND created_at < ‘2026-11-05’,索引才能正常发挥作用。
第三,LIKE ‘%关键词%’ 以通配符开头时同样走不了普通索引,因为索引是有序的,前缀不确定就无法定位。确实需要全文检索时,应该用 FTS5 虚拟表,而不是在普通列上硬加索引。

养成习惯:改前改后各看一次
流程固定下来只有三步:先跑 EXPLAIN QUERY PLAN 确认是 SCAN 还是 SEARCH;按“等值条件在前、排序列在后”的顺序建复合索引;改完再跑一次,确认扫描消失、排序消失。很多“加了索引还是慢”的问题,根源都是只做了第二步、没做第一步和第三步。
索引是工具,不是信仰。让执行计划先说话,再决定加什么、加在哪,查询优化才不会变成凭感觉的玄学。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。