`

数据库性能调优技术—深入理解单表执行计划

 
阅读更多
一、概述

    这篇文章是数据库性能调优技术的第二篇。上一篇讲解的索引调优是数据库性能调优技术的基础。这篇讲解的深入理解单表执行计划,是数据库性能调优的有力工具。

查询语句可以有多种可选执行计划,如何选择效率最高的执行计划?达梦数据库、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 * from t1 where c1=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 it1c1 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 index it1c1;

create unique index uit1c1 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 where c1〉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〉2 order 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操作符?

  不是。

  比如,查询语句“select c1 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列上创建索引从而查询速度变快。那么在执行计划中是如何体现的呢?

  查询语句“select max(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(*) from t1;”的执行原理一样。XEVL是表达式计算,本文不进行讲解。



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

  查询语句“select c1,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操作?

  查询语句“select c2,count(*) from t1 where c2〉=2 group 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(*),如果是其它的分组函数,处理过程类似。
分享到:
评论

相关推荐

    数据库性能调优技术2深入理解单表执行计划.pdf

    在数据库性能调优的众多领域中,单表执行计划的深入理解是至关重要的一个环节。本文将详细探讨数据库单表执行计划的相关概念、技术和实际案例,特别以达梦数据库、Oracle数据库和SQLServer数据库为实例,深入解析...

    数据库性能调优.原理与技术

    《数据库性能调优:原理与技术》是一本深入探讨如何提升数据库系统运行效率的专业书籍。在信息化社会中,数据库作为存储和处理数据的核心组件,其性能优化对于企业业务的高效运行至关重要。本书全面覆盖了数据库性能...

    《数据库性能调优--原理与技术》

    《数据库性能调优--原理与技术》是一本深入探讨数据库性能优化的专业书籍,旨在帮助读者理解和掌握提升数据库系统效率的关键技术和方法。通过学习本书,读者能够有效地解决在实际工作中遇到的数据库性能问题,提高...

    数据库性能调优--原理与技术2.pdf

    《数据库性能调优——原理与技术2》这本书专注于Oracle数据库的性能优化,通过深入探讨其内部机制和技术细节,为读者提供了实用的优化策略和最佳实践。 **数据库性能调优的目的**主要包括: - 提高查询响应速度,...

    数据库性能调优技术--索引调优

    ### 数据库性能调优技术——索引调优 #### 一、概述 随着信息技术的快速发展,数据库在各行各业的应用越来越广泛,对于数据处理速度和效率的要求也越来越高。数据库性能调优是一项涉及多方面知识的综合性技能,它...

    oracle 数据库性能调优技术 2 中文

    ### Oracle数据库性能调优技术之深入理解单表执行计划 #### 概述 在数据库管理与维护工作中,性能调优是一项关键技能。特别是在大型企业级应用中,Oracle数据库的性能直接影响到系统的整体运行效率和用户体验。...

    数据库性能调优 原理与技术

    本文将深入探讨“数据库性能调优:原理与技术”这一主题,涵盖数据库设计、查询优化、索引策略、存储优化等多个方面。 首先,数据库性能优化的基础是良好的数据库设计。这包括合理的数据模型设计,如选择合适的数据...

    db2数据库性能调优

    【DB2数据库性能调优】 在数据库管理领域,性能优化是一项关键任务,特别是对于像IBM DB2 Universal Database (UDB)这样的大型企业级数据库系统。本文档深入探讨了如何使用Java示例程序PERFORMER来监控和优化DB2 ...

    oracle 数据库性能调优技术 3 中文

    ### Oracle数据库性能调优技术——深入理解嵌套循环执行计划 #### 一、概述 本文是关于Oracle数据库性能调优技术系列文章的第三篇。在前一篇中,我们详细探讨了单表执行计划的重要性及其对多表执行计划理解的基础...

    数据库性能调优技术系列

    数据库性能调优是IT领域中的一个关键话题,特别是在大数据时代,高效、稳定的数据处理能力直接影响着业务的运行效率。本系列将深入探讨如何优化数据库性能,以提高数据存取速度,减少延迟,提升整体系统响应时间。...

    oracle数据库性能调优(3)

    本篇将继续深入探讨Oracle数据库性能调优的诸多方面,重点关注于嵌套循环执行计划,这是数据库多表操作中常见的连接方式之一。 首先,了解单表执行计划是理解多表执行计划的基础,单表执行计划涉及到了对单个表进行...

    数据库性能调优-原理与技术

    本文将深入探讨数据库性能调优的基本原理和技术方法,帮助读者更好地理解和掌握这一领域的核心知识。 #### 一、数据库性能调优概述 **1.1 性能调优的重要性** 随着数据量的不断增长以及业务需求的变化,数据库...

    oracle 数据库性能调优技术 4 中文

    ### Oracle数据库性能调优技术之散列连接执行计划 #### 概述 本文是数据库性能调优技术系列的第四篇文章,旨在深入探讨散列连接在Oracle数据库中的运用及其原理。在上一篇中,我们详细讨论了嵌套循环连接执行计划...

    数据库性能调优--原理与技术.rar

    这个压缩包文件“数据库性能调优--原理与技术”很可能包含了关于如何优化数据库性能的深入讲解和实用技术。下面将详细讨论数据库性能优化的一些主要方面。 1. **查询优化**:查询优化是性能调优的基础,涉及到SQL...

Global site tag (gtag.js) - Google Analytics