当前位置: 首页 > news >正文

04总结-索引

目录

一、索引的取舍:什么时候“多建”,什么时候“克制”

二、SQL 基本结构 & EXPLAIN QUERY PLAN

基本 SQL 结构

EXPLAIN QUERY PLAN 用法

看懂几句关键输出

控制优化器的“指令”

三、联合索引 & 左前缀匹配 & 范围截断

左前缀匹配

ORDER BY 与索引顺序

范围条件切断(Range Terminates Order)

四、典型业务场景的索引设计

1. 点查 / 详情页

2. 列表页(过滤 + 排序 + 分页)

3. 搜索框 / 前缀 LIKE

4. IN / OR 条件

5. DISTINCT / GROUP BY

6. 倒序取最新

五、高级索引:表达式 / 部分 / 覆盖

1. 表达式索引(解决“函数导致索引失效”)

2. 部分索引(热点数据单独建索引)

3. 覆盖索引(只用索引、不回表)

六、优化器与维护:优化器、ANALYZE、VACUUM、PRAGMA

ANALYZE

VACUUM

常用 PRAGMA 开关

七、常见坑 & 使用习惯

八、SQLite 的 WITHOUT ROWID:什么时候用

九、子查询 vs JOIN & EXPLAIN

十、DISTINCT & ORDER BY

十一、多值条件与子查询写法

同一列多值

大子查询 + 关联条件

对索引列少做函数 / 计算

十二、调优流程模板(拿去就能用)


一、索引的取舍:什么时候“多建”,什么时候“克制”

索引 = 给数据库加“目录 / 索引页”
让查东西更快,但要多占空间、写入变慢。

面试要点:什么时候“多建”,什么时候“克制”

  • 读多写少(比如报表系统、日志分析):
    → 倾向于多建索引,查询体验更重要。

  • 写多读少(比如高频写入的日志表、流水记录):
    → 要克制建索引,避免写入性能崩掉。


二、SQL 基本结构 & EXPLAIN QUERY PLAN

基本 SQL 结构

SELECT ... 
FROM ... 
WHERE ... 
ORDER BY ...;

EXPLAIN QUERY PLAN 用法

在上面那句前面加一行 EXPLAIN QUERY PLAN

EXPLAIN QUERY PLAN 
SELECT ... FROM ... WHERE ... ORDER BY ...;

看懂几句关键输出

  • SCAN TABLE user
    → 没用索引,整表一扫。

  • SEARCH TABLE user USING INDEX idx_user_email (email=?)
    → 用了索引,按 email 查,效率较高。

  • USING COVERING INDEX
    → 查询需要的列在索引里就够了,不用回表。

  • USE TEMP B-TREE FOR ORDER BY
    → 为了排序,额外创建了临时结构,说明没用索引满足排序。

  • EXECUTE LIST SUBQUERY
    → 在执行你写的子查询。

控制优化器的“指令”

  • INDEXED BY 索引名:强制用指定索引。

  • NOT INDEXED:这次别用索引。

  • PRAGMA optimize:整体稍微调优一下。


三、联合索引 & 左前缀匹配 & 范围截断

左前缀匹配

CREATE INDEX idx (a, b, c);

可以覆盖以下前缀:

  • WHERE a = ?

  • WHERE a = ? AND b = ?

  • WHERE a = ? AND b = ? AND c = ?

  • WHERE b = ? ❌(不能跳过 a)

范围条件示例:

  • WHERE a > ? AND b = ?
    a 是范围,后面的 b 通常失效。

ORDER BY 与索引顺序

  • ORDER BY a ASC, b ASC
    能被 INDEX(a, b) 吃下,无需额外排序。

范围切断示例:

  • WHERE user_id = ? AND status = ?
    → (a, b) 全用。

  • WHERE user_id > ? AND status = ?
    → a 用了“范围”,截断了,b 只能当普通过滤条件,索引帮不上多大忙。

范围条件切断(Range Terminates Order)

a 用了范围> < BETWEEN LIKE 'x%')后,a 之后的列不再用于等值匹配或排序

例如:

INDEX(a, b);
WHERE a > ? AND b = ?;

这里的 b 通常无法继续利用索引。

设计联合索引时:

  • 把等值过滤多、选择性高的列放前面;

  • 把范围列放后面。


四、典型业务场景的索引设计

1. 点查 / 详情页

WHERE email = ?;
  • 用 UNIQUE / 主键索引。

  • 必要时做覆盖索引 (email, id, ...)

2. 列表页(过滤 + 排序 + 分页)

WHERE user_id = ? AND created_at BETWEEN ... 
ORDER BY created_at DESC;

→ 索引设计:INDEX(user_id, created_at DESC [ , 其他展示列…])

3. 搜索框 / 前缀 LIKE

WHERE name LIKE 'abc%';  -- 可以用索引

INDEX(name)

忽略大小写:

  • 建索引:INDEX(LOWER(name))

  • 查询:WHERE LOWER(name) LIKE 'abc%'

4. IN / OR 条件

  • col IN (...) → 单列索引基本能用。

  • 复杂 OR → 拆成多条 SQL 用 UNION ALL

5. DISTINCT / GROUP BY

  • DISTINCT col / GROUP BY colINDEX(col) 帮你少排序、少折腾。

6. 倒序取最新

ORDER BY created_at DESC LIMIT 20;

INDEX(created_at DESC)


五、高级索引:表达式 / 部分 / 覆盖

1. 表达式索引(解决“函数导致索引失效”)

问题:

WHERE REPLACE(phone, '-', '') = ...  -- 导致普通索引用不上

方案:

CREATE INDEX idx_user_phone_clean ON user(REPLACE(phone, '-', ''));

注意: 查询里的表达式必须和索引里的完全一致。


2. 部分索引(热点数据单独建索引)

问题:
只常用查 status = 'PAID' 的订单,别的状态不常查。

方案:

CREATE INDEX idx_order_paid 
ON orders(user_id, created_at) 
WHERE status = 'PAID';

要点: 查询条件要包含这个 status='PAID'(或更强),索引才会被用。


3. 覆盖索引(只用索引、不回表)

场景: 列表页只查 id, created_at, amount

方案:

CREATE INDEX idx_order_list 
ON orders(user_id, created_at DESC, id, amount);

在 EXPLAIN 里看到 USING COVERING INDEX 就是命中覆盖索引。


六、优化器与维护:优化器、ANALYZE、VACUUM、PRAGMA

优化器 = 数据库里的“路线规划师”
专门负责“怎么执行 SQL 才又快又省”。

  • ANALYZE / VACUUM / PRAGMA
    = 给这个路线规划师提供最新地图、打扫道路、调一些开关。

ANALYZE

  • 大改数据后跑一下,让优化器“重新认识”表的大小和分布,少瞎选执行计划。

VACUUM

  • 删除很多数据后,做一次大扫除,回收磁盘、减少碎片。

常用 PRAGMA 开关

  • case_sensitive_like:LIKE 是否区分大小写,影响索引使用。

  • automatic_index:允许 SQLite 临时帮你建索引救急。

  • foreign_keys:外键约束,和性能无关,但和数据正确性强相关,建议开


七、常见坑 & 使用习惯

  • WHERE 里别随便 函数(索引列)
    不是不能用,是要么改成范围,要么建“表达式索引”。

  • LIKE 想用索引,前面不能是 %
    xxx% 行,%xxx 不行。

  • 联合索引:等值列在前,范围列在后

  • 那种取值很少、分布很平均的列(性别、布尔值)一般不要单独建索引。

  • 深分页别用 OFFSET 999999,改用“基于上一页最后一条记录继续往下翻”的方式(基于游标 / 上一条主键)。

  • 尽量不要无脑 SELECT *,尤其是列表页和热点接口。

  • 事务里少放耗时操作,否则容易“锁住全场”。


八、SQLite 的 WITHOUT ROWID:什么时候用

普通表:

  • 都有隐藏的 rowid,所有索引最后都指向 rowid,再通过 rowid 找到真实数据。

WITHOUT ROWID:

  • 会直接用主键作为表的 B-Tree key,主键既是逻辑键,也是物理定位键:

    • 少一层跳转;

    • 少存一个 rowid B-Tree。

适用场景:

  • 一般在 联合主键、读多写少、对体积敏感 的场景考虑,比如一些多列主键的中间表。


九、子查询 vs JOIN & EXPLAIN

  • 子查询:在 SQL 里再套一层查询,表达“先查 A 再用 A 查 B”,直观但有时会慢,尤其是相关子查询。

  • JOIN:多表拼在一起查,结构化、适合复杂多表查询,也更容易被优化器好好优化。

  • EXPLAIN:让你看到数据库打算怎么执行这条 SQL,用来分析性能、检查索引是否生效。

子查询 vs JOIN 的选择:

  • 谁更容易用上已有索引,就用谁;

  • 子查询慢就改 JOIN,JOIN 复杂就改子查询,试 EXPLAIN 看执行计划。


十、DISTINCT & ORDER BY

  • DISTINCT:去掉重复的行,只保留“唯一值”。

  • ORDER BY:把结果按某个字段(或多个字段)排个顺序。

  • 一起用时:先去重,再排序,常见于“查所有不重复的 XX,并按字母/时间/大小排好”。

少用无意义的 DISTINCT / ORDER BY:

  • 确定本来就唯一就别 DISTINCT;

  • 不需要排序就别 ORDER BY。


十一、多值条件与子查询写法

同一列多值

  • a IN (?,?,?) 优于 a=? OR a=? OR a=?

大子查询 + 关联条件

EXISTS (SELECT 1 FROM ... WHERE ... AND o.user_id = u.id
)

往往比:

user_id IN (SELECT user_id FROM ...)

更适合利用索引。

对索引列少做函数 / 计算

  • 改成范围或预先计算好的值;

  • 必要时用表达式索引,而不是在 WHERE 里乱包函数。


十二、调优流程模板(拿去就能用)

  1. 明确需求:过滤条件、排序字段、返回列、数据量级与写入比。

    • 过滤条件:WHERE 里会按什么筛?user_idstatuscreated_at

    • 排序字段:要怎么排?ORDER BY created_at DESC

    • 返回列:真的需要哪些列?是 id, amount, created_at,还是你懒得想直接 SELECT *

    • 数据量级:这表是 1 万行、100 万行还是 1 亿行?

    • 读写比例:读多写少?(偏向多建索引)还是写多读少?(谨慎加索引)

  2. 写出“理想索引”
    等值放前,范围放后;尽量覆盖常用列。

  3. EXPLAIN QUERY PLAN
    看是否出现 SCAN / 临时排序 / 是否 COVERING INDEX。

    • 有没有 SCAN TABLE xxx → 表示在全表扫,索引没用上;

    • 有没有 USE TEMP B-TREE FOR ORDER BY → 说明在额外排序,没用索引顺序;

    • 有没有 USING COVERING INDEX ... → 说明命中了覆盖索引,性能一般不错。

    目的:看现在的实际执行计划,跟你“理想状态”差在哪儿。

  4. 按计划修索引
    加 / 改索引顺序,必要时用表达式索引 / 部分索引。

  5. 跑 ANALYZE
    让优化器获取新统计。

  6. 压测与回归:观测实际延迟、IO、写入成本。

    • 这条 SQL 的耗时是不是明显下降了?

    • QPS 提升了吗?RT 降了多少?

    • IO 是否减少?(读盘次数、页数)

    • 写入速度有没有被新的索引拖慢太多?(INSERT/UPDATE 变慢没?)

    同时做回归验证:

    • 有没有影响其他 SQL?比如新索引让另一个查询选了个更差的计划;

    • 业务结果是否正确。

    → 验证“看起来很美”的改动,在现实里是不是真的美。

  7. 长期维护
    数据分布变化大时重跑 ANALYZE,定期清理冷索引。
    调优不是“一次性作业”,而是“长期维护”——数据变,你的索引方案也要跟着进化

http://www.dtcms.com/a/618357.html

相关文章:

  • 3C硬件:数码相机从入门到落地
  • 网站后台会员管理百度资讯
  • 设计企业的网站wordpress seo插件教程
  • 做DNN的建议 -- 过拟合篇
  • 旅游网站的广告预算怎么做规划设计公司起名
  • Elasticsearch高阶用法实战:从数据建模到集群管控的极致优化
  • exec() 族函数使用
  • 小程序公众号网站建设网站建设费用怎么入账
  • 基于MATLAB的滑膜观测器仿真搭建
  • 学生评教|高校评教|基于SpringBoot+vue高校学生评教系统 (源码+数据库+文档)
  • 深圳网站开发外包网站登录系统源码
  • wordpress acg站一个网站的建设需要哪些流程图
  • 40.华为云企业网站上云部署核心服务功能与用法总结
  • 推荐微商城网站建设河北邯郸大风
  • 中间件设计规范及安装手册
  • 网站开发合同预期中国百强城市榜单发布2021
  • Vgent:基于图的多模态检索推理增强生成框架GraphRAG,突破长视频理解瓶颈
  • MATLAB基于RBF神经网络与DE-NSGAII算法的钢轨闪光焊工艺参数优化
  • Vue3 watch 家族:watch、watchEffect、watchPostEffect 全梳理
  • 仿RabbitMQ实现消息队列(四)--sqlite3与gtest快速上手
  • 昆明网站建设_云南网站建设有网址的公司
  • 做网站后面维护要收钱吗如何做品牌运营与推广
  • 网络安全 | 深入解析CSRF攻击与防御实战
  • 动态网站发布部署核心问题详解
  • 基于RTT调试接口的项目适配性的lib库化实现与工程应用
  • 解决Blender新加面后不跟随骨骼移动(骨骼权重的绘制)
  • 深圳光明网站建设今天福州发生的重大新闻
  • Android 自定义「阶段进度条(步轴)」实践
  • 【第三阶段-核心功能开发:UI进阶】第七章:主题系统-就像室内设计师
  • discuz 手机网站wordpress 搜索自定义数据表字段