SQL优化的一些基本概念
文章背景:
在单表查询的场景下,SQL语句可能走索引,可能走全表扫描。为了提升SQL执行的效率,我们需要制造条件让SQL语句按照效率较高的执行计划执行。在制造条件的背景下,我们需要先判断怎么样的执行计划是高效的,进而需要了解一些基础的概念,具体内容如下:
基数:
数据表中,某列唯一键的数量叫做基数。主键列的基数等于表的总行数,基数的高低影响列的数据分布。
以达梦数据库安装完毕后,生成示例库中的某表为例,表结构如下:
由上图可以确认,该表的主键列为city_id,接下来我们看一下该表的数据。如下图:
该表共有11行记录,city_id列各行记录的值不同,根据我们所介绍的基数的概念,可以得出dmhr.city表中city_id列的基数为11。
同理,region_id列的基数是多少呢?请看下图:
该表中,Region_id列的基数为7。
或者我们用一个直观的方法看一下这张表下所有列的基数。请看下图:
通过上图这个sql可以看到该表下各个列对应的基数值,同时也可以确认regin_id列存在重复值。
将基数的概念具体化以后,我们换一张数据量大一些的测试表来讨论一些问题。
表test共有1111行记录,Type$列唯一键的数量为6(基数为6),说明该列存在大量重复数据。id列唯一键的数量为1111(基数为1111)。同时,与表的总行数一致,说明可以在该列上增加主键约束。
那type$列上的数据分布到底是怎么样的呢,我们使用sql语句做一查询,具体内容如下图:
根据上图中的查询结果,我们发现type$列的数据分布并不均匀,schobj这个值对应416行记录,tabobj对应363行记录,等等。
基数的高与低是相对于该表的总行数来说的,在test表中,type$列的基数确实处在低的这个维度。然而前面提到基数的高低影响了数据的分布,从上图中我们也得到了证实。
但是,基数的高与低,针对于我们这篇文章的背景有什么意义呢?
在说明上述问题前,我们先抛出一个问题,如下:
select * from test where id=?
语句中,?代表可以传入任何值,那上述sql应该走索引还是全表扫描呢?
select * from test where type$=?
同样,?代表可以传入任何值,那这第二条sql该走索引还是全表扫描呢?
答案其实很简单,id列的基数等于表的行数,则?不论传入什么值,返回的结果应该都是一行,此时选择性低,过滤度高,使用索引是最优选择。
同理,type$列的返回值并不一定,按照本文中查到该列的数据分布来看,有可能返回1、12、23、296、363、416行记录。则此时选择率不是确定的值,在这种情况下SQL语句的执行有可能使用索引、有可能使用全表扫描。
选择率:
在刚才的答案中,我们引出了一个概念:选择率。同时也暗含了一个索引和全表扫描到底该怎么选择的规则,如下:
单表查询中,返回结果集小的情况下,建议使用索引。返回结果集大的情况下,建议使用全表扫描。返回结果集是表中数据5%内时我们可以看作小的情况,反之。当然,5%并不是一个绝对的值。
在了解规则以后,我们就可以介绍选择率这个概念了。
选择率:基数与总行数的比值再乘以100%就是某个列的选择率。通过上文中的内容我们也不难看出,在进行SQL优化的时候,单看列的基数是没有意义的,需要结合总行数才有实际的意义。换句话说,可能是由于选择率才有了基数这个概念。
接下来我们再看一个问题,以下两个图显示的是语句select * from test where type$=‘SCHOBJ’;的执行计划,哪一个图的执行计划是合适的,不合适的执行计划究竟为什么不合适呢?
图1:
图2:
答案是:图二是合适的执行计划。
图一中结果集是27,这和我们之前查到的结果返回是不匹配的,优化器在这样的统计信息下无法给出准确的执行计划,基于我们之前提到的规则来判定为走索引。在更新统计信息后,我们得到了图二的执行计划,再看时已经发现匹配出正确的结果集,同时给出了合适的执行计划。
通过这个问题我们带出了两个概念:统计信息、执行计划。
统计信息:
统计信息的作用是为了让优化器选择最佳执行计划,以最少的代价得到查询结果。
统计信息主要分为表的统计信息、列的统计信息、索引的统计信息,除此之外还有系统的、数据字典的、动态性能视图的统计信息。我们重点要关注的是表、列、索引这三类统计信息。
表的统计信息主要包含表的总行数、表的块数、表的行平均长度。
列的统计信息主要包含列的基数、列中空值数量、列的数据分布情况。
索引的统计信息主要包含索引高度、叶子块个数等。
执行计划:
执行计划是SQL语句的执行方式,来自于优化器,优化器制定计划的依据则是统计信息。
SQL优化是一个可深可浅的领域,掌握基本的概念是基石,为未来进一步的深入做好准备。
文章
阅读量
获赞