数据持久化与缓存 / 技术笔记

SQL 查询与索引

从查询结果开始,理解数据库如何寻找数据,以及索引为什么能加速也会带来成本。

内容章节
6 节
阅读重点
查询与执行计划
示例语言
SQL

SQL 和普通程序代码有一个明显区别:我们通常描述“想得到什么”,数据库决定“怎样得到”。

SQL 示例

sql

SELECT title, created_atFROM articlesWHERE status = 'published'ORDER BY created_at DESC;

这条语句没有规定先扫哪一页数据,也没有规定使用哪个索引。这些属于查询优化器的工作。

写 SQL 先保证结果正确,再理解数据库为了得到结果做了多少工作。

1. SQL 查询是在描述结果

一条查询可以按逻辑步骤理解:找到数据来源,筛选行,组合字段,分组,最后排序和限制数量。

SQL 示例

sql

SELECT category_id, COUNT(*) AS article_countFROM articlesWHERE status = 'published'GROUP BY category_idORDER BY article_count DESC;

实际执行顺序可能不同,因为优化器会寻找成本更低的方案,但查询表达的结果不应该改变。

2. JOIN 为什么容易写错

JOIN 连接的是两组行。如果连接条件不完整,结果数量可能突然变大。

SQL 示例

sql

SELECT o.id, u.nicknameFROM orders AS oJOIN users AS u ON u.id = o.user_id;

INNER JOIN 只保留两边都匹配的数据,LEFT JOIN 会保留左表全部数据。选择哪一种,取决于“没有关联数据时,这一行还要不要出现”。

3. 索引像书本目录

没有索引时,数据库可能需要从第一行看到最后一行。索引会保存有序的键和值所在的位置。

SQL 示例

sql

CREATE INDEX idx_articles_statusON articles(status);

索引能加快读取,但插入和更新时也要维护。低区分度字段单独建索引不一定有效,最终仍要结合真实查询判断。

4. 联合索引为什么讲究顺序

联合索引可以理解成先按第一列排序,再在相同值中按第二列排序。

SQL 示例

sql

CREATE INDEX idx_articles_status_createdON articles(status, created_at);

它适合下面这种查询:

SQL 示例

sql

SELECT id, titleFROM articlesWHERE status = 'published'ORDER BY created_at DESCLIMIT 20;

列顺序应该围绕常见筛选和排序设计,随意堆叠字段会增加维护成本并降低索引价值。

5. EXPLAIN 怎样定位慢查询

EXPLAIN 会展示数据库准备怎样执行查询。

SQL 示例

sql

EXPLAINSELECT id, titleFROM articlesWHERE status = 'published'ORDER BY created_at DESCLIMIT 20;

重点关注访问方式、选择的索引、预估扫描行数,以及是否需要额外排序或临时表。执行计划提供优化线索,需要结合真实耗时和数据量一起判断。

6. 从慢查询到优化的完整过程

遇到慢查询时,可以按这个顺序处理:

文本示意

text

记录真实 SQL 和参数确认结果是否可以减少查看 EXPLAIN检查筛选、连接和排序字段设计或调整索引在接近生产的数据量上重新测量

不要只凭感觉增加索引。优化应该有修改前后的耗时、扫描行数和执行计划作为依据。