UniqueKey:让你的查询跑的更快

简介: UniqueKey:让你的查询跑的更快

执行计划的好坏对于查询的性能起着至关重要的影响,那么一个执行计划的生成都和哪些因素相关? 内容简要 1. 什么是Uniquekey 2. 进一步识别UniqueKey 3. UniqueKey的应用和实践 UniqueKey是在一个结果集中能够唯一确定一条记录的一组表达式,对于一个复杂的查询,这个结果集通常是执行到一定阶段的中间结果集。 比如说有一个5张表连接,第一个阶段是每一个结果的单个结果集,在这个阶段每一张表都有自己的UniqueKey,当第一张表和第二张表建立之后,建立的结果又有一个怎样的UniqueKey?前三张表建立之后它的UniqueKey是怎么样的,整个过程中都可以判断它的UniqueKey是什么样,基于这些信息,优化器可以做出更加明智的决断! ![image.png](https://ucc.alicdn.com/pic/developer-ecology/e5c4ac27a28f446cb20fea457269dfdc.png)

UniqueKey=Unique Index

 

UniqueKeyUnique Index有很强的关联性,通常UniqueKey的起点就是Unique Index,但它们是不同的,首先从简单的例子看起:

image.png

这种场景是UniqueKey的最简单的场景,那么a是唯一的UniqueKey吗?

答案是否定的,因为唯一索引允许有多个空值存在。A并不是唯一的,因为Unique Index允许多个NULL。排除NULL的因素即可。

 

如何去保证一个Unique Index出来的结果是不包含空的:

第一种场景是在定义表结构的时候,列上面就有非空约束,就可以很清楚的判断它里边一定不会有空值;第二种判断会根据用户输入的查询,就是在表里它可能会存在多个空值,但是对于这个结果集里边a它一定不会有空值存在;第三种Select a from t where a in一个子查询。如果a是一个空a in子查询,一定也不会返回True。所以a它也一定不是是空的;第四种就会不那么直观,它是Select a from t where func(a)大于10,并且函数它的Isstrict的属性是TrueIsstrict的属性True它表达的意思是如果它的输入参数a是一个空,那么它的返回值一定也是空,那么它的返回值就一定不会大于10

也可以简单的说,唯一索引再加上一个非空约束,最终就可以转变为一个唯一键。例如下图所示:

image.png

再看一个组合索引的情况,如下图所示:

image.png

至此为止讨论的都是唯一键和单表查询,实际上更复杂的场景来自于表连接。来看一个两张表连接的例子,如下图:

image.png

对于这样的一个结果集,它里边是没有唯一键的,那么对于一个表查询来说,它的唯一键在哪些场景下面是可以继承下来的呢?其他场景会产生UniqueKey的例子,如下图:

image.png

在现实场景中的UniqueKey会隐藏在一个复杂查询中的一部分。需要在一个执行计划的产生过程中,在任何一个阶段准确判断出UniqueKey的属性,以便优化器产生更优的执行计划。

image.png

UniqueKey的用途

 

唯一键的用途?

第一减少半连接;

第二减少无用连接;

第三可以去除一些不需要的Distinct操作。

 

 

1.减少半连接  如下图所示:

image.png

image.png

这里的t2100万条数据,要把这100万条数据全部扫描一遍,根据执行情况,可以看到它执行的时间是372毫秒。

image.png

整个过程中只对于t整个循环了10次,而不是原来的100万次,它的执行时间也从原来的370多毫秒下降到了0.235毫秒。

但为什么前面的就不能这样做,后面的这个就可以这样做呢?

原因在于 a它是一个唯一键,而 b不是唯一键,在 a是一个唯一键的场景下面,可以做一些查询的改写。

 

半连接的转化过程如下:

本来是Select from t2 wehre b inSelect a from t )它可以将这个半连接转换成一个正常的Inner JoinSelect t2. from t2,t where t2.b=t.a,这里的t2.b=t.aa又是一个UniqueKey通过这样的教育,并不会让原来的t2的一条结果变成多条结果,所以这个语义还是相等的。 当把它们转变成一个正常的连接以后,优化器就会同时去看,拿着t2去教育t生成一些执行计划,也会拿着t去教育t2去生成另外的一批执行计划。

最后优化器会认为拿着t去教育t2可以得到一个更好的执行计划,也就是前面看到的,扫描外表只有10行,整个过程中只需要循环10次即可达到目的。

这里查询的改写依赖于 a它是一个唯一键。

image.png

2.减少无用连接:

最终出现的这样的一个查询的逻辑分析的一个结果,就是在这种场景下面,t2里边的任何的一个结果集都不会被重复,并且每一条数据都应该被返回,并且都不会被重复,这个结构可以直接去扫描一下,t2t1没有任何的关系。

最终可以看到对于 Left Join这样的操作,产生的一个执行计划,仅仅是对t2进行了一个全表扫描和 t没有任何的关系。

 

那么用户为什么会写一个这样的查询?会写出这种没有用的连接语句呢?

 

实际上这是一个使用场景,假设有一个表,它有很多的属性,这些属性全部放到一起,表就会非常的大,而这个时候可以把一个宽表拆分成很多的窄表,然后拆分成窄表以后,如果是只去访问其中的个别列的话,其实是访访问了一个更小的结果集,它的性能就会更好。

但有一样是不变的,就是说每个人如果想去获得更多的列,他就要去写很多不同的Join,这个时候其实有一种做法,创建一个视图,把所有的表全部通过Left键把它给连接起来,这个时候用户看到的是一个像宽表一样的,它只有去查询这个视图,去检索它需要的量。如果说它只检索很少的量,优化器就会直接通过这项技术把那些无关的表的Left那些Join全部给去掉,性能也会变得很好,用户也会非常的方便。在PG内部的优化视图里边,内置的一些视图里边很多都采用了这样的技术。

image.png

Join会使得一方的结果集过滤掉或者一行变多行。

.Left Join保证了左表的数据一定不会被过滤掉。

.Join右表的条件又是UniqueKey,所以左表的数据一定不会被重复。

.最终只需要扫描一遍t2即可,完全忽略掉t1.

实用场景:将一个宽表拆分面多个窄表,然后通过left join来创建视图,应用按需检索列。

 

消除无用的Distinst操作

正常的 Distinst的操作,Select Distinst a c d首先要得到一个结果集,然后对结果集进行一次去除,如果它的数据量是很大的,这个去除它本身也可能要花费很长的时间,但是如果说可以判断出这个结果集已经是唯一的了,去重操作是可以不做的。看右边的查询,它是Select Disstind b c d那么a本来就是唯一的,加上cd,它自然还是唯一的Distinst的操作。可以完全忽略这样的操作,省掉了一个代价很高的节点。

这样一个功能的意义在现实生活中,在平时开发应用程序的时候,有可能也会进行很多的表连接,当创建完表连接以后,其实也很难判断它到底是不是唯一的,这个时候就会去加一个Distinct的操作,同时有一些框架也比较适合去加这种Distinct的操作。

 

 

如果数据库的内核识别不了这些唯一键,它就必须要去生成一个去除的节点,可能要消耗很大的资源,但是如果说能够识别这样的一个信息,这个节点就可以直接去除,从而达到很好的性能。如下图所示:

 image.png

阿里云在今年1月份的时候提交了一个Patch Patch可以更加系统化的去识别,在一个复杂阶段的UniqueKey,它的唯一键是什么?

相对提供了一个非常完整的监测机制,同时又增强了一个Distinct的操作。将UniqueKey用于Distinct的这种场景下边。这个功能有望会在PGConf和入到PGConf14这个版本里边。

image.png

PolarDB(兼容PG/Oracle语法)

特点:

-计算存储分离

-计算节点点瞬间扩容

-存储节点按量收费

-高度兼容Oracle语法

image.png

它是一个一写多读的架构,但和传统的主备不同,它采用的是计算存储分离的架构,并且底层是一个共享的文件系统Polar Store

这种架构的好处是计算存储分离,计算节点可以做到瞬间的扩容,并且存储节点也可以按量付费。

在语法层面,我们高度兼容Oracle语法,用户可以轻易的从Oracle数据库迁移到Polar Store,在读节点和写节点之上,还有一个MaxSQL节点,用户只需要连接MaxSQL节点,就会根据当时的准备延迟情况,将请求转发给读写节点或者只读节点,从而充分的利用硬件资源。

相关文章
|
2月前
|
SQL 分布式计算 运维
如何对付一个耗时6h+的ODPS任务:慢节点优化实践
本文描述了大数据处理任务(特别是涉及大量JOIN操作的任务)中遇到的性能瓶颈问题及其优化过程。
|
6月前
|
SQL 存储 关系型数据库
原本可以执行得很快的 SQL 语句,执行速度却比预期的慢很多,原因是什么?如何解决?
原本可以执行得很快的 SQL 语句,执行速度却比预期的慢很多,原因是什么?如何解决?
|
27天前
|
SQL 运维
Doris同一个SQL任务,前一天执行成功,第二天执行失败
Doris 动态分区 插入数据 同样的代码隔天运行一个成功一个失败
|
SQL 存储 缓存
如何让JOIN跑得更快(下)
如何让JOIN跑得更快
114 0
如何让JOIN跑得更快(下)
|
SQL 存储 算法
如何让JOIN跑得更快(上)
如何让JOIN跑得更快
99 0
如何让JOIN跑得更快(上)
|
SQL XML Java
线上sql执行慢,分享3个优化案例
线上sql执行慢,分享3个优化案例
211 0
|
SQL 存储 物联网
如何使用SQL任务计算房间电量消耗的实践案例
文本介绍一例物联网平台数据服务SQL洞察用于智能家居的实践案例
|
SQL 关系型数据库 MySQL
mysql查询优化实战:查询用时一分半降到三毫秒
项目中的课程预约记录查询功能,线下门店反馈说进入到页面需要等2分钟
mysql查询优化实战:查询用时一分半降到三毫秒
|
SQL 存储 缓存
如何让JOIN跑得更快
如何让JOIN跑得更快
130 0
如何让JOIN跑得更快
|
数据库
第八周课后作业 数据库查询练习
第八周课后作业 数据库查询练习
第八周课后作业 数据库查询练习