数据库工作机制

查询处理机制(Query Planner)

查询处理的概念

查询处理 是指数据库系统从接收到一条 SQL 语句开始,到最终返回结果的整个执行过程。
它决定了:

  • 数据如何被检索;

  • 查询如何被优化;

  • 最终如何高效地执行。

各阶段详解

在 PostgreSQL 中,查询处理包括以下主要阶段:

SQL → 解析(Parsing) → 重写(Rewriting) → 优化(Optimization) → 执行(Execution)

PostgreSQL查询处理的具体步骤:

1
2
3
4
5
6
7
8
9
10
11
用户SQL查询

1️⃣ 解析器 Parser

2️⃣ 语义分析 & 重写器 Rewriter

3️⃣ 优化器 Optimizer

4️⃣ 执行器 Executor

返回结果集

解析(Parsing)

将 SQL 字符串解析为一棵 语法分析树(Parse Tree)。
任务:

  • 检查语法是否正确;
  • 验证表、列、函数是否存在;
  • 生成表示 SQL 结构的内部树形结构。

例如:

1
SELECT name, salary FROM employees WHERE department = 'IT';

解析后得到的语法树中包含:

  • 查询类型(SELECT)
  • 投影列(name, salary)
  • 来源表(employees)
  • 过滤条件(department=’IT’)

如果语法或标识符错误,此阶段会抛出错误。

重写(Rewriting)

根据系统规则(主要来自视图、规则系统)重写语法树。
任务:

  • 视图展开成实际查询;

  • 应用规则(RULE)系统;

  • 转换等价的 SQL 表达式。

优化(Optimization)

在众多执行方案中选择 代价最小(Cost Lowest) 的方案。是 PostgreSQL 查询处理的 核心与最复杂部分。

优化器的主要任务:

  • 确定 连接顺序(Join Order)
  • 选择 索引扫描、顺序扫描、嵌套循环 等策略
  • 计算每种方案的 代价(cost)
  • 选出 最优执行计划(Plan)

PostgreSQL 使用 基于代价的优化器(Cost-Based Optimizer, CBO)
它会基于统计信息(表大小、列分布、索引信息等)来估算代价。

执行(Execution)

根据优化器生成的计划,实际从存储中读取数据并返回结果。

执行器(Executor)负责:

  • 访问存储层(表文件、索引文件);
  • 逐行评估 WHERE 条件;
  • 进行聚合(GROUP BY)、排序(ORDER BY);
  • 处理连接(JOIN);
  • 输出结果集。

查看真实的执行时间与计划的估算对比:

1
EXPLAIN ANALYZE SELECT ...

EXPLAIN

EXPLAINPostgreSQL 中用于显示查询执行计划的语句。
它不会真正执行 SQL,而是告诉你 PostgreSQL 打算如何执行这条查询。

基本用法:

1
EXPLAIN [ (option [, ...]) ] statement

常见选项(option):

选项 作用
ANALYZE 真正执行查询并显示真实运行时间、行数等(默认只显示计划)
VERBOSE 显示更详细的计划信息(包括输出列等)
BUFFERS ANALYZE 模式下,显示缓冲区的读写情况
COSTS 显示代价估计(默认启用)
TIMING 是否显示每个节点的耗时(默认开启)
FORMAT 指定输出格式:TEXT, JSON, YAML, XML

执行计划主要字段解释

字段 含义
Node Type 执行节点类型(如 Seq Scan, Index Scan, Nested Loop 等)
Relation Name 表名
Startup Cost 启动代价(开始输出第一行的成本)
Total Cost 总代价(输出完所有行的成本)
Rows 估计的输出行数
Width 估计的每行字节数
Actual Time 实际执行时间(仅在 ANALYZE 模式下)
Actual Rows 实际输出的行数
Buffers 缓冲区访问情况

常见执行节点(Node Type)

节点类型 含义
Seq Scan 顺序扫描整张表(未使用索引)
Index Scan 使用索引扫描表
Bitmap Index Scan + Bitmap Heap Scan 使用位图索引(适合返回多行)
Nested Loop 嵌套循环连接(适合小表 + 大表)
Hash Join 基于哈希的连接(适合大表连接)
Merge Join 基于排序的连接(输入必须有序)
Aggregate 聚合操作(如 SUM、COUNT)
Sort 排序操作
Limit 限制输出的行数

示例

1
EXPLAIN SELECT * FROM employees WHERE department_id = 5;

输出可能如下:

1
2
Seq Scan on employees  (cost=0.00..25.00 rows=5 width=100)
Filter: (department_id = 5)

表示 PostgreSQL 计划进行顺序扫描(Seq Scan),估计代价为 0 到 25。

再看看 ANALYZE 模式下的例子:

1
2
EXPLAIN (ANALYZE, BUFFERS) 
SELECT * FROM employees WHERE department_id = 5;

结果:

1
2
3
4
5
6
Seq Scan on employees  (cost=0.00..25.00 rows=5 width=100)
Actual time=0.010..0.045 rows=3 loops=1
Filter: (department_id = 5)
Buffers: shared hit=5
Planning Time: 0.150 ms
Execution Time: 0.060 ms

这里可以看到:

  • 实际扫描的行数 (rows=3)
  • 实际耗时 (Execution Time)
  • 缓冲区命中数 (Buffers)
  • Copyrights © 2023-2025 Hexo

请我喝杯咖啡吧~

支付宝
微信