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

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

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

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

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. 嵌套循环算法
    • 外层表每一行,都和内层表每一行比较,像双重循环:
      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课程的学生姓名

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

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表  

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

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

-- 先从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

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

在这里插入图片描述

相关文章:

  • 设计模式-依赖倒置原则(Dependency Inversion Principle, DIP)
  • Spring Boot(九十一):Spring Boot实现防盗链功能
  • WPS 和 office (word/excel/ppt) 找到模板所在位置以及更改模板的方式(公文写作格式要求、字体安装、模板下载)
  • Maven高级学习笔记
  • 常见哈希格式类型及其在CTF与渗透测试中的爆破与伪造策略(PBKDF2、bcrypt...)
  • Spring Boot分布式锁深度优化:彻底解决达梦数据库高并发死锁问题
  • 【C++11】智能指针——unique_ptr, shared_ptr和weak_ptr
  • DBeaver数据库管理工具的简介、下载安装与优化配置
  • 【Dify精讲】第10章:会话管理与上下文保持【知识卡片】
  • Nginx入门篇
  • 【计算机网络】:get与post
  • 基于协同过滤的新高考志愿个性化智能推荐系统前后端讲解
  • 座舱监控系统(In-Cabin Monitoring System,IMS)相关知识
  • Gartner发布终端安全项目路线图:保护终端免受复杂网络攻击
  • 前端项目如何部署为https
  • 每天一个前端小知识 Day 3 - JavaScript 的作用域与闭包
  • C++指针的使用
  • 计算机网络 期末实训 eNSP 校园网
  • AI 在智慧农业领域的 10 大应用:从作物监测到精准营销
  • React前端与React Native移动端开发须知差异
  • 网站建设的市场/怎么建立一个自己的网站
  • 国内做航模比较好的网站/网站流量分析
  • 苹果网站导航条/有什么平台可以发布推广信息
  • 朝阳专业网站建设/网络推广内容
  • 网站目的及功能定位/设计网站排行榜前十名
  • 社交网站开发语言/厦门seo小谢