热门标签 | HotTags
当前位置:  开发笔记 > 数据库 > 正文

数据库性能调优技术

一、概述这些内容,我会在后续的几篇文章中进行详细的描述。在此之前,我们首先需要掌握如何理解数据库执行计划。这篇文章讲解只涉及单表操作的执行计划。达梦数据库、oracle数据库、sqlserver数据库都可以显示给定语句的执行计划。我详细分析了这三个数

一、概述 这些内容,我会在后续的几篇文章中进行详细的描述。在此之前,我们首先需要掌握如何理解数据库执行计划。这篇文章讲解只涉及单表操作的执行计划。达梦数据库、oracle 数据库、sql server 数据库都可以显示给定语句的执行计划。我详细分析了这三个数


一、概述

这些内容,我会在后续的几篇文章中进行详细的描述。在此之前,我们首先需要掌握如何理解数据库执行计划。这篇文章讲解只涉及单表操作的执行计划。达梦数据库、oracle 数据库、sql server 数据库都可以显示给定语句的执行计划。我详细分析了这三个数据库的执行计划,三者之间并无本质区别。所以本文的内容适合于这三个数据库。同样,也应该适合绝大多数其它的数据库。

单表执行的深入理解,是了解多表执行计划的基础。达梦数据库显示的执行计划时显示的信息会多一些。因此,这篇文章中我选择达梦数据库作为实例数据库来讲解执行计划的原理。读完本文后,应该能够读懂这三个数据库的单表执行计划。

二、深入理解数据库执行计划

达梦数据库的执行计划有两种显示方式:第一种为图形化的显示方式;第二种为文本式的显示方式。这里采用第二种方式进行讲解。理解执行计划,是迈向理解数据库性能调优的重要一步。从执行计划中,我们可以看出数据库是如何执行查询语句,并根据执行计划判断出该查询语句的执行是否高效,以及如何进行优化。

下面我们将通过一些例子来理解数据库执行计划

1.没有索引的全表扫描过滤如何执行?

构造处执行场景:

create table t1(c1 int,c2 int);

insert into t1 values(1,1);

insert into t1 values(2,2);

insert into t1 values(3,3);

insert into t1 values(4,4);

insert into t1 values(5,5);

insert into t1 values(6,6);

查询语句为:

select * fromt1 wherec1=2;

该语句的执行过程,如果用语言描述可以描述成这样:

1)如果是第一次执行该步骤,则取得表的第一条记录;否则取得当前记录的下一条记录。如果记录已经扫描结束,则执行步骤 4,否则执行步骤 2。

2)判断该记录是否满足过滤条件c1=2,满足则执行步骤 3,否则执行步骤 1。

3)把该记录放到结果集中,执行步骤1。

4)将结果集返回给客户端。

实际上,数据库执行查询语句的过程也是类似的,下面是该查询语句的执行计划:

#RSET:[21, 1, 1];

#XFLT:[0, 0, 0]; EXPR0 = 2

#CSEK:[21, 1, 1]; INDEX33555545(T1),FULL_SCAN

该执行计划中出现的内容,在此做出解释:

1)CSEK(查找)类似于上文中描述的步骤1,方括号中的内容是执行该操作的评估代价,本文不作分析。“INDEX33555545(T1)”说明使用了 T1 表的聚集索引, “FULL_SCAN”表示对聚集索引 INDEX33555545(T1)进行全扫描。这里需要注意的是,达梦数据库中的表默认情况下是索引组织的。如果建表时指定了 cluster primary key,那么数据以该 clsuter primary key 组织数据,否则以 rowid 组织数据。

2)XFLT(过滤)类似于上文中描述的步骤 2,“EXPR0 = 2”是过滤条件。

3)RSET(结果集)类似于上文中描述的步骤 3,用来存放符合条件的记录集。

我们可以看出,数据库的执行过程和我们用语言描述的步骤是一致的。

该查询语句完整的执行流程如下:

1)CSEK 取得第一条记录(1,1)传给 XFLT,将控制权传给 XFLT。

2)XFLT 发现该记录(1,1)不符合条件,将控制权传给 CSEK。

3)CSEK 取得下一条记录(2,2)传给 XFLT,将控制权传给 XFLT。

4)XFLT 发现记录(2,2)符合条件,将该记录传给 RSET,将控制权传给 RSET。

5)RSET 将记录(2,2)放入结果集,将控制权传给 XFLT。

6)XFLT 给控制权传给 CSEK。

7)CSEK 取得下一条(3,3)传给 XFLT,将控制权传给 XFLT。

8)XFLT 发现该记录(3,3)不符合条件,将控制权传给 CSEK。

9)CSEK 取得下一条(4,4)传给 XFLT,将控制权传给 XFLT。

10)XFLT 发现该记录(4,4)不符合条件,将控制权传给 CSEK

11)CSEK 取得下一条(5,5)传给 XFLT,将控制权传给 XFLT。

12)XFLT 发现该记录(5,5)不符合条件,将控制权传给 CSEK。

13)CSEK 取得下一条(6,6)传给 XFLT,将控制权传给 XFLT。

14)XFLT 发现该记录(6,6)不符合条件,将控制权传给 CSEK。

15)CSEK 发现描述操作已经结束,通知 XFLT 结束。将控制权传给 XFLT。

16)XFLT 得知查询操作结束,通知 RSET 结束。将控制权传给 RSET。

17)RSET 得知操作结束。

18)发送结果集(包含记录(2,2))给客户端。

2.如果表 t1 上的 c1 列有非唯一索引,如何执行呢?

表 t1 的定义以及数据和 1 中描述的一样。

创建索引: create index it1_c1 on t1(c1);

查询语句“select* from t1 where c1=2;”对应的执行计划为:

#RSET:[201, 2, 1];

#CSEK(SECOND):[201, 2, 1]; IT1C1(T1), INDEX_EQU_SEARCH

CSEK 行的“SECOND”表示使用非聚集索引“IT1C1”,对该索引进行索引等值(INDEX_EQU_SEARCH)查找。

该执行计划的执行流程为:

1)CSEK 使用 c1=2 查找非聚集索引,得到第一条 c1=2 的索引记录(2,rowid1)中的 rowid1(为数值)。使用 rowid1 查找聚集索引得到对应的数据记录(2,2)传递给 RSET,将控制权传给 RSET。

2)RSET 将记录(2,2)放入结果集,将控制权传给CSEK。(因为 c1 上的索引是非唯一的,所以可能出现两条以上的记录满足c1=2,所以需要将控制权传给CSEK)。

3)CSEK 取得当前非聚集记录的下一条记录(3,rowid2),因为3!=2,所以扫描结束。将控制权传给RSET。(如果满足 c1=2 的记录数大于1条,需要继续传递记录给 RSET,以此类推,直到遇到不满足c1=2 的那条记录,结束操作。)

4)RSET 得知操作结束。

5)发送结果集(包含记录(2,2))给客户端。

3.如果表 t1 上的 c1 列有唯一索引,如何执行呢?

首先删除 c1 列上的非唯一索引,然后在 c1 列上创建唯一索引:

drop indexit1 c1;

create uniqueindex uit1 c1 on t1(c1);

查询语句“select* from t1 where c1=2;”对应的执行计划为:

#RSET:[201, 2, 1];

#CSEK(SECOND):[201, 2, 1]; UIT1C1(T1), INDEX_EQU_SEARCH

该执行计划的执行流程为:

1)CSEK 使用 c1=2 查找非聚集索引,得到 c1=2 的索引记录(2,rowid1)中的rowid1(为数值)。使用 rowid1 查找聚集索引得到对应的数据记录(2,2)传递给 RSET, 将 控制权传给 RSET。(当然,有人也许会问,如果没有记录满足 c1=2怎么办呢?那么, 此处什么记录都不传递给RSET,通知RSET查询操作结束,最后返回空集给客户端)。

2)RSET 将记录(2,2)放入结果集,操作结束(因为是唯一索引,所以最多只有 1 条记录满足 c1=2)。

3)发送结果集(包含记录(2,2))给客户端。

这里我们发现,例3使用了唯一索引,例2使用了非唯一索引。例3的执行速度大于例2的执行速度。

4.如何理解执行计划中的 top n 操作?

查询语句“select top 10 * from t1 wherec1>2;”对应的执行计划为:

#RSET:[21, 1, 1];

#XTOP:[0, 0, 0]; top_off(0), top_num(10)

#XFLT:[0, 0, 0]; EXPR1 > 2

#CSEK:[21, 1, 1]; INDEX33555545(T1),FULL_SCAN

XTOP(取得前 N 条记录):将 XFLT 操作符传递来的记录放入到 RSET(结果集)中,并判断记录数是否已经等于给定值 10(语句中的 top 10)。如果已经等于 10,则查询已经执行成功,退出。否则将控制权限传给 XFLT,继续执行。依次执行,直到取得 10 条记录,或者表CSEK操作已经查询结束(即符合条件的记录不满 10 条)。

5.如何理解执行计划中的 order by 操作?

查询语句“select top 10 * from t1 where c2>2order by c1;”对应的执行计划为:

#RSET:[21, 1, 1];

#XSORT:[0, 0, 0]; keys_num(1),is_distinct(FALSE)

#XFLT:[0, 0, 0]; EXPR1 > 2

#CSEK:[21, 1, 1]; INDEX33555545(T1),FULL_SCAN

XSORT(对记录进行排序):将 XFLT 操作符传递来的记录插入到 XSORT 维护的临时空间中的合理位置,按 c1 进行有序排列。然后将控制权传给 XFLT 以取得下一条符合条件的记录。等处理完所有符合条件的记录。XSORT操作符才会将控制权限传给 RSET。

6.是不是查询语句中一旦出现 order by 字句,执行计划中就会出现 XSORT 操作

符?

不是。比如,查询语句“selectc1 from t1 order by c1;”对应的执行计划为:

#RSET:[0, 0, 0];

#CSEK:[0, 0, 0]; UIT1C1(T1), FULL_SCAN

从执行中我们可以看出,达梦直接对索引 UIT1C1进行全索引扫描,对于得到的每一条记录不需要进行 XSORT 排序操作,直接放入 RSET(结果集)中。因为索引 UIT1C1 本身就是按照 c1 进行排序的。

7.有文档说,对于语句“select max(c1) from t1”,可以在 c1 列上创建索引从而查询速度变快。那么在执行计划中是如何体现的呢?

查询语句“selectmax(c1) from t1”对应的执行计划:

#RSET:[0, 0, 0];

#XEVL:[0, 0, 0];

#FAGR:[0, 0, 0]; function_num(1)

在这个执行计划中,我们没有看到 CSEK 操作符。因为 c1 上存在索引 UIT1C1,该索引叶子节点的最右端就是 c1 的最大值。FARG 直接返回该最大值。语句“select min(c1) from t1;”、语句“select count(*) fromt1;”的执行原理一样。XEVL是表达式计算,本文不进行讲解。

8.如果列上存在索引,如何理解中的 group by 操作?

查询语句“selectc1,count(*) from t1 where c1>=2 group by c1;”对应的执行计划为:

#RSET:[11, 1, 1];

#XEVL:[0, 0, 0];

#SAGR:[0, 0, 0]; group_by_num(1),function_num(1)

#CSEK:[11, 1, 1]; UIT1C1(T1), INDEX_GE_SEARCH

我们可以得到,CSEK使用了索引UIT1C1进行了范围查找。首先传递给SARG的是连续的 c1=2 的记录组,然后是 c1=3 的记录组,然后是 c1=4 的记录组,……

此处 SARG 的执行流程是

1)从 CSEK 取得一条 c1=2 记录,将计数加 1,

2)从 CSEK 取得下一条记录,如果该记录满足 c1,将计数+1。

3)重复执行步骤 2,直到取得第一条不满足 c1=2 的记录,将(2,对应的计算)传递给 XEVL,再传给 RSET(结果集)。接着对 c1=3 的记录组执行同样的流程。依此类推,直到处理完所有符合条件的记录。

这里我们的分组函数是count(*),如果是其它的分组函数,处理过程类似。

9.如果列上不存在索引,如何理解中的 group by 操作?

查询语句“selectc2,count(*) from t1 where c2>=2group by c2;”对应的执行计划为:

#RSET:[21, 1, 1];

#XEVL:[0, 0, 0];

#HAGR:[0, 0, 0]; group_by_num(1),function_num(1)

#XFLT:[0, 0, 0]; EXPR0 >= 2

#CSEK:[21, 1, 1]; INDEX33555550(T1),FULL_SCAN

这里因为 c2 上没有索引,HARG 的作用是 HASH 分组。

HARG 的执行流程是:

1)从 XFLT 取得一条记录

2)记录的 c1=m,如果在 hash 表中已经对应项,计数+1,如果不存在对应项,在创建一个新的 hash 项。

3)所有的符合过滤条件的记录处理完成之后,HARG 才会将控制权限传给上层操作符,HARG 每次向上层操作符传递一条(m,m 对应的计数)。

这里我们的分组函数是 count(*),如果是其它的分组函数,处理过程类似。

推荐阅读
  • 本文介绍如何从包含多个记录的会员表中,筛选出同时拥有BookID为10和14的会员。通过SQL查询语句,可以有效地获取符合条件的MemberID。 ... [详细]
  • 在进行QT交叉编译时,可能会遇到与目标架构不匹配的宏定义问题。例如,当为ARM或MIPS架构编译时,需要确保使用正确的宏(如QT_ARCH_ARM或QT_ARCH_MIPS),而不是默认的QT_ARCH_I386。本文将详细介绍如何正确配置编译环境以避免此类错误。 ... [详细]
  • 本文深入探讨了SQL数据库中常见的面试问题,包括如何获取自增字段的当前值、防止SQL注入的方法、游标的作用与使用、索引的形式及其优缺点,以及事务和存储过程的概念。通过详细的解答和示例,帮助读者更好地理解和应对这些技术问题。 ... [详细]
  • Oracle中NULL、空字符串和空格的处理与区别
    本文探讨了在Oracle数据库中使用NULL、空字符串('')和空格('_')时可能遇到的问题及解决方案。重点解释了它们之间的区别,以及在查询和函数中的行为。 ... [详细]
  • Oracle 数据导出为 SQL 脚本的详细步骤
    本文介绍如何使用 PL/SQL Developer 工具将 Oracle 数据库中的数据导出为 SQL 脚本,包括详细的步骤和注意事项。 ... [详细]
  • 简化报表生成:EasyReport工具的全面解析
    本文详细介绍了EasyReport,一个易于使用的开源Web报表工具。该工具支持Hadoop、HBase及多种关系型数据库,能够将SQL查询结果转换为HTML表格,并提供Excel导出、图表显示和表头冻结等功能。 ... [详细]
  • 1.介绍有时候我们需要一些模拟数据来进行测试,今天简单记录下如何用存储过程生成一些随机数据。2.建表我们新建一张学生表和教师表如下:CREATETABLEstudent(idINT ... [详细]
  • 1.执行sqlsever存储过程,消息:SQLServer阻止了对组件“AdHocDistributedQueries”的STATEMENT“OpenRowsetOpenDatas ... [详细]
  • 在Fedora 31上部署PostgreSQL 12
    本文详细介绍如何在Fedora 31操作系统上安装和配置PostgreSQL 12数据库。包括环境准备、安装步骤、配置优化以及安全设置,确保数据库能够稳定运行并提供高效的性能。 ... [详细]
  • 本文介绍了解决在Windows操作系统或SQL Server Management Studio (SSMS) 中遇到的“microsoft.ACE.oledb.12.0”提供程序未注册问题的方法,特别针对Access Database Engine组件的安装。 ... [详细]
  • PostgreSQL 最新动态 —— 2022年4月6日
    了解 PostgreSQL 社区的最新进展和技术分享 ... [详细]
  • 本文详细介绍了MySQL数据库中的Bin Log和Redo Log,阐述了它们在日志记录机制、应用场景以及数据恢复方面的区别。通过对比分析,帮助读者更好地理解这两种日志文件的作用和特性。 ... [详细]
  • 本章详细介绍SP框架中的数据操作方法,包括数据查找、记录查询、新增、删除、更新、计数及字段增减等核心功能。通过具体示例和详细解析,帮助开发者更好地理解和使用这些方法。 ... [详细]
  • 在安装 SQL Server 时,选择混合验证模式可以提供更高的灵活性和管理便利性。如果您已经安装了 SQL Server 并使用单一的 Windows 身份验证模式,可以通过以下步骤将其更改为混合验证模式。 ... [详细]
  • 本文介绍了在 SQL Server 2012 客户端中格式化 SQL 查询语句的多种方法,包括内置功能和第三方工具,帮助用户提高代码可读性和维护性。 ... [详细]
author-avatar
拍友2502882315
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有