数据库系统概论(十九)详细讲解关系查询处理与查询优化

数据库系统概论(十九)详细讲解关系查询处理与查询优化

  • 前言
  • 一、关系数据库系统的查询处理
    • [1. 关系代数基础](#1. 关系代数基础)
    • [2. 为什么查询优化很重要?](#2. 为什么查询优化很重要?)
    • [3. 查询处理的四个核心步骤](#3. 查询处理的四个核心步骤)
    • [4. 选择运算算法](#4. 选择运算算法)
    • [5. 连接运算算法](#5. 连接运算算法)
    • [6. 索引](#6. 索引)
  • 二、关系数据库系统的查询优化
    • [1. 数据库查询的"目标"](#1. 数据库查询的“目标”)
    • [2. 集中式数据库](#2. 集中式数据库)
      • [2.1 最"费劲儿"的:磁盘存取(I/O代价)](#2.1 最“费劲儿”的:磁盘存取(I/O代价))
      • [2.2 处理机"算题"的时间(CPU代价)](#2.2 处理机“算题”的时间(CPU代价))
      • [2.3 临时"桌子"的空间(内存代价)](#2.3 临时“桌子”的空间(内存代价))
    • [3. 分布式数据库](#3. 分布式数据库)
      • [3.1 总代价 = 集中式的三种代价 + 通信代价](#3.1 总代价 = 集中式的三种代价 + 通信代价)
  • 三、代数优化
    • [1 为什么需要"等价变换"?](#1 为什么需要“等价变换”?)
    • [2 什么是"等价"的查询?](#2 什么是“等价”的查询?)
    • [3. 代数优化的"黄金法则"](#3. 代数优化的“黄金法则”)
    • [4. 以例题为例:看优化如何"提速"](#4. 以例题为例:看优化如何“提速”)
      • [4.1 初始语法树:"笨办法"的执行逻辑](#4.1 初始语法树:“笨办法”的执行逻辑)
      • [4.2 优化后的语法树:"聪明办法"的执行逻辑](#4.2 优化后的语法树:“聪明办法”的执行逻辑)
    • [5. 练习:查"数据库原理"课程的学生姓名](#5. 练习:查“数据库原理”课程的学生姓名)
    • [6. 启发式优化的核心思想:"少算、早算、合并算"](#6. 启发式优化的核心思想:“少算、早算、合并算”)
  • 四、物理优化
    • 一、什么是物理优化
    • [2. 物理优化的两种"策略"](#2. 物理优化的两种“策略”)
    • [3. 数据库统计信息从哪来?](#3. 数据库统计信息从哪来?)
    • [4. 基于启发式规则常用"经验法则"](#4. 基于启发式规则常用“经验法则”)
    • [5. 基于代价估算的优化](#5. 基于代价估算的优化)
      • [1. 全表扫描的代价:](#1. 全表扫描的代价:)
      • [2. 索引扫描的代价:](#2. 索引扫描的代价:)
      • [3. 嵌套循环连接的代价:](#3. 嵌套循环连接的代价:)
      • [4. 排序-合并连接的代价:](#4. 排序-合并连接的代价:)

前言

  • 在前几期博客中,我们探讨了 SQL 连接查询,单表查询,嵌套查询,集合查询,基于派生表的查询,数据插入,修改与删除,空值的处理,视图,数据库安全性,数据库规范化与五大范式,数据库设计的概念技术等知识点。
  • 从本节开始,我们将深入讲解关系查询处理与查询优化。

我的个人主页,欢迎来阅读我的其他文章
https://blog.csdn.net/2402_83322742?spm=1011.2415.3001.5343

我的数据库系统概论专栏
https://blog.csdn.net/2402_83322742/category_12911520.html?spm=1001.2014.3001.5482


一、关系数据库系统的查询处理

1. 关系代数基础

在数据库中,查询的本质是对数据的操作,而关系代数是描述这些操作的数学工具。先记住三个最常用的运算:

  1. 选择(σ):从表中筛选符合条件的行,比如"选选修81003课程的记录"。
  2. 投影(π):从表中选取需要的列,比如"只取学生姓名"。
  3. 连接(⋈):将多个表按关联条件合并,比如"按学号合并学生表和选课表"。

例子:查询"选修81003课程的学生姓名",用SQL写是:

sql 复制代码
SELECT Sname FROM Student, SC WHERE Student.Sno=SC.Sno AND SC.Cno='81003';

用关系代数可以写成三种形式,而它们的执行效率天差地别:

  • Q1:先算笛卡尔积(Student×SC),再筛选和投影 → 最慢
  • Q2:先连接再筛选 → 中等
  • Q3:先筛选SC表,再连接和投影 → 最快

2. 为什么查询优化很重要?

假设Student表有1000行,SC表有10000行,选修81003的记录有50行

  1. Q1的执行过程

    • 先算笛卡尔积:1000×10000=1000万行,需要读写2100个数据块,耗时约105秒;
    • 再筛选和投影:读写1000万行数据,总耗时约10^5秒(27小时!)。
  2. Q3的执行过程

    • 先筛选SC表:只取50行,读SC表耗时5秒;
    • 再连接Student表:只查50个学生,读Student表耗时5秒;
    • 总耗时约10秒,比Q1快10000倍

3. 查询处理的四个核心步骤

当你写下一条SQL时,数据库后台会经历以下流程:

  1. 查询分析
    • 像语文老师一样分析句子结构,检查SQL语法是否正确(比如关键字是否写错)。
  2. 查询检查
    • 语义检查:确认表和列是否存在(比如Student表是否存在);
    • 权限检查:确认用户有权限查询这些数据;
    • 视图转换:如果涉及视图,把视图展开成实际表的操作。
  3. 查询优化
    • 代数优化:调整操作顺序(如先筛选再连接),减少数据量;
    • 物理优化:选择最佳执行算法(如用索引扫描代替全表扫描)。
  4. 查询执行
    • 生成执行代码,按优化后的计划读取和处理数据。

4. 选择运算算法

场景:从Student表中找"2000年以后出生的学生"。

  1. 全表扫描法
    • 像翻书一样逐行检查,适合小表。
    • 缺点:如果表有100万行,要查100万次,很慢。
  2. 索引扫描法
    • 像查字典目录,先通过索引(如B+树)找到符合条件的"页码"(元组指针),再直接取数据。
    • 例子:若Birthdate列有索引,查"2000-01-01之后出生",只需查索引中大于该值的区间,直接定位数据块。

5. 连接运算算法

场景:合并Student和SC表,按学号关联。

  1. 嵌套循环算法
    • 外层表每一行,都和内层表每一行比较,像双重循环:

      python 复制代码
      for 学生 in Student表:
          for 选课 in SC表:
              if 学生学号 == 选课学号: 合并两行
    • 缺点:若Student有1000行,SC有10000行,要比较1000万次,耗时严重。

  2. 排序-合并算法
    • 先把两张表按学号排序,再按顺序匹配(类似归并排序):
      1. 排序Student和SC表的学号;
      2. 依次取Student的一个学号,快速找到SC中相同学号的所有行。
    • 优点:只需扫描两张表各一次,大大减少比较次数。
  3. 索引连接算法
    • 若SC表的学号有索引,对Student的每一行,直接通过索引查SC中的匹配行,无需全表扫描。

6. 索引

如果SC表的Cno列有索引,查询"选修81003课程"时:

  • 无需扫描10000行SC表,只需通过索引找到Cno='81003'的50行,I/O次数从100次(全表扫描)减少到3-4次,时间从5秒降到0.1秒!

二、关系数据库系统的查询优化

1. 数据库查询的"目标"

不管是哪种数据库,当你用它查东西时(比如查"张三的成绩"),数据库系统都在默默做一件事:

  • 用尽可能少的资源消耗,把结果快速找出来

就像你找东西时,会想"怎么找最省事",数据库也在算"怎么查最省钱(这里的'钱'是计算机的资源)",这个过程就叫"查询优化"。

2. 集中式数据库

集中式数据库,就像所有数据都存在一台电脑里(比如你电脑里的Excel文件),它查东西时的"力气消耗"主要有三种:

2.1 最"费劲儿"的:磁盘存取(I/O代价)

  • 比如你要从硬盘里找数据,硬盘像个大仓库,数据存在不同的"货架格子"(磁盘块)里。数据库要找到这些格子,把数据读出来,这个"搬东西"的过程很花时间,是最主要的开销。
  • 例子:查1000条数据,要是它们分散在1000个不同的磁盘块里,就得搬1000次,比集中在10个块里慢得多。

2.2 处理机"算题"的时间(CPU代价)

  • 数据读出来后,计算机的CPU要处理这些数据(比如排序、筛选),就像你拿到一堆纸条后,要一张张看并挑出符合条件的,这需要时间。

2.3 临时"桌子"的空间(内存代价)

  • 数据在读出来处理时,会先放在内存里(像临时桌子),如果数据太多,内存不够用,就需要来回倒腾,也会拖慢速度。

3. 分布式数据库

分布式数据库,就像数据存在很多台电脑里(比如一个公司的信息存在10台服务器上),这时候查东西除了上面三种开销,还多了一个"通信代价":

3.1 总代价 = 集中式的三种代价 + 通信代价

  • 比如你要查的数据分布在3台服务器上,数据库需要先让这3台服务器各自查自己的数据,然后把结果"传话"(网络传输)给负责汇总的服务器。
  • 通信代价就像:你和朋友分工找东西,找到后要互相告诉对方结果,打电话、发消息的时间和流量就是"开销"。如果传的数据量很大(比如10GB),或者服务器之间网络很慢,这个开销会非常大,甚至比前三种加起来还高。

三、代数优化

1 为什么需要"等价变换"?

想象你要算"(2+3)×4",直接算和拆成"2×4+3×4"结果一样,但后者可能更简单。关系代数的"等价变换"就是这个道理:把复杂的查询表达式变成执行效率更高的形式,结果不变,但速度更快。

2 什么是"等价"的查询?

两个查询表达式如果输出的结果完全一样,就说它们"等价"。比如:

  • 表达式A:先查所有学生,再筛选"男生";
  • 表达式B:先筛选"男生",再查所有学生;
  • 它们的结果都是"所有男生的信息",所以A≡B。

3. 代数优化的"黄金法则"

数据库优化最核心的策略就一句话:尽可能早地过滤掉不需要的数据

就像你去超市买苹果,先直奔水果区(筛选),而不是先逛遍整个超市再找苹果(最后筛选)。

4. 以例题为例:看优化如何"提速"

原SQL:查选修81003课程的学生姓名

sql 复制代码
SELECT Sname FROM Student, SC WHERE Student.Sno=SC.Sno AND SC.Cno='81003';

4.1 初始语法树:"笨办法"的执行逻辑

复制代码
    结果(取姓名)  
     ↓  
    投影(Sname)  
     ↓  
    筛选(SC.Cno='81003')  
     ↓  
    连接(Student和SC按学号)  
     ↓  
    Student表       SC表  

问题:先连接两张表(可能产生1000×10000=1000万行),再筛选,最后投影。中间数据量极大,耗时严重。

4.2 优化后的语法树:"聪明办法"的执行逻辑

复制代码
    结果(取姓名)  
     ↓  
    连接(Student和筛选后的SC)  
     ↓  
    Student表    筛选(SC.Cno='81003')  

优化点:先筛选SC表(只留50行选修81003的记录),再和Student表连接,数据量从1000万行降到1000×50=5万行,速度提升200倍!

5. 练习:查"数据库原理"课程的学生姓名

SQL

sql 复制代码
SELECT SNAME FROM Student, Course, SC  
WHERE Student.sno=SC.sno AND Course.cno=SC.cno AND Cname='数据库原理';

画初始语法树:从SQL到"执行蓝图"

复制代码
        结果(取SNAME)  
         ↓  
    project(SNAME)  
     ↓  
    筛选(Cname='数据库原理')  
     ↓  
    连接(Course和SC按课程号)  
     ↓  
    连接(Student和SC按学号)  
     ↓  
Student表     SC表     Course表  

逻辑:先连接三张表(可能产生大量中间数据),再筛选课程名,最后取姓名。

优化第一步:先筛选"数据库原理"课程

sql 复制代码
-- 先从Course表找到"数据库原理"的课程号  
σ_{Cname='数据库原理'}(Course)  

优化第二步:先连接Course和SC,再连Student

复制代码
        结果(取SNAME)  
         ↓  
    project(SNAME)  
     ↓  
    连接(Student和中间结果)  
     ↓  
Student表    连接(筛选后的Course和SC)  
     ↓  
σ_{Cname='数据库原理'}(Course)    SC表  

优化逻辑

  1. 先从Course表筛选出"数据库原理"的课程(假设只有1行);
  2. 用这门课的课程号连接SC表(只查选这门课的记录,假设50行);
  3. 再用SC的学号连接Student表(查50个学生的姓名);
  4. 全程数据量从"三张表笛卡尔积"降到"1×50×1000=5万行",效率大幅提升。

6. 启发式优化的核心思想:"少算、早算、合并算"

  1. 少算:能先筛选就先筛选,减少参与运算的数据量;
  2. 早算:把筛选、投影等操作尽量提前,别等到最后;
  3. 合并算:投影和筛选可以同时进行(比如扫描表时同时挑列和行),避免重复读数据。

四、物理优化

一、什么是物理优化

之前学的代数优化,解决的是"先查什么、后查什么"的逻辑问题(比如先筛选再连接)

  • 而物理优化,解决的是"用什么方式查"的具体问题,就像你决定了"去超市买苹果"后,要选"开车""走路"还是"骑车"------不同方式效率不同。

2. 物理优化的两种"策略"

  1. 基于启发式规则的优化(拍脑袋)
    • 凭经验选方法,比如"有索引就先用索引""大表连接用排序合并法"。
    • 优点:简单快速;缺点:可能不是最优解。
  2. 基于代价估算的优化(算成本)
    • 计算每种方法的执行"成本"(如I/O次数、CPU时间),选成本最低的。
    • 优点:精准;缺点:计算量大。

3. 数据库统计信息从哪来?

数据库有个"数据字典",像小本本一样记着所有表和索引的"简历":

  1. 表的信息
    • 比如Student表有1000行(N=1000),每行100字节(l=100),占100个磁盘块(B=100)。
  2. 列的信息
    • 比如SC表的Cno列有100种不同课程(m=100),选"81003"课程的概率是5%(选择率f=0.05)。
  3. 索引的信息
    • 比如Sno列的B+树索引有3层(L=3),叶节点有50个(Y=50),每个索引值对应10行数据(选择基数S=10)。

4. 基于启发式规则常用"经验法则"

(1)选择操作(筛选数据)的经验:

  • 有索引就用索引:比如查"Sno=20180001",若Sno有索引,直接通过索引找,比全表扫描快。
  • 结果集大就全表扫描:如果筛选条件返回80%的行(如查"性别=男",而表中80%是男生),索引反而可能更慢,不如全表扫描。

(2)连接操作的经验:

  • 小表连大表,用嵌套循环:比如Student(1000行)和SC(10000行)连接,把小表Student放外层循环,减少内层循环次数。
  • 大表连大表,用排序合并或哈希连接:先排序或哈希分组,避免嵌套循环的百万次比较。

5. 基于代价估算的优化

1. 全表扫描的代价:

  • 公式:读表的磁盘块数(B),假设每秒读20块,代价=B/20秒。
  • 例子:Student表占100块,全表扫描代价=100/20=5秒。

2. 索引扫描的代价:

  • 公式:索引层数(L)+ 数据块数。比如B+树索引L=3层,找到数据后读5个磁盘块,总代价=3(查索引)+5(读数据)=8次I/O。
  • 例子:查"Sno=20180001",索引3层,数据占1块,代价=3+1=4次I/O,比全表扫描(100块)快得多。

3. 嵌套循环连接的代价:

  • 公式:外层表块数(B1) + 外层表行数(N1)× 内层表块数(B2)。
  • 例子:Student(B1=100块,N1=1000行)连SC(B2=100块),代价=100 + 1000×100=100100次I/O,非常慢!

4. 排序-合并连接的代价:

  • 公式:排序两张表的代价 + 扫描两张表的代价。假设排序代价各100秒,扫描各100块,总代价=100+100+100+100=400秒,比嵌套循环(100100次I/O≈5000秒)快很多。

以上就是这篇博客的全部内容,下一篇我们将继续探索更多精彩内容。

我的个人主页,欢迎来阅读我的其他文章
https://blog.csdn.net/2402_83322742?spm=1011.2415.3001.5343

我的数据库系统概论专栏
https://blog.csdn.net/2402_83322742/category_12911520.html?spm=1001.2014.3001.5482

|--------------------|
| 非常感谢您的阅读,喜欢的话记得三连哦 |

相关推荐
Tapdata3 小时前
全球 DaaS 市场研究报告上线,聚焦数据服务化趋势与行业演进路径
数据库
李少兄4 小时前
MySQL 默认连接数
数据库·mysql
刘一说4 小时前
资深Java工程师的面试题目(六)数据存储
java·开发语言·数据库·面试·性能优化
江沉晚呤时4 小时前
EventSourcing.NetCore:基于事件溯源模式的 .NET Core 库
java·开发语言·数据库
liulun5 小时前
SQLite官方数据库加密方案
数据库·sqlite
小五Z5 小时前
MySQL--InnoDB存储引擎--架构
数据库·mysql
远方160917 小时前
40-Oracle 23 ai Bigfile~Smallfile-Basicfile~Securefile矩阵对比
数据库·人工智能·sql·oracle·矩阵·database
汪子熙20 小时前
HSQLDB 数据库锁获取失败深度解析
数据库·后端
无色海1 天前
mysql连接生命周期-连接阶段
数据库