达梦数据库DM8-多表连接学习分享

这里再放一个达梦云适配中心链接,里面的文档模块有很多官方教程,社区模块也可以查询或者提出各类使用问题
达梦在线服务中心


前言

  何为连接查询,我们可以广义认为查询语句中 FROM 子句包含多个表时,称为连接查询。如 SELECT * FROM t1,t2 就是连接查询。
  连接是关系数据库模型的主要特点,也是它区别于其它类型数据库管理系统的一个标志,在关系数据库管理系统中,表建立时各数据之间的关系不必确定,常把一个实体的所有信息存放在一个表中。当检索数据时,可以通过连接查询出存放在多个表中的不同实体的信息。
(本文主要是基于本人对于达梦数据库的多表连接查询学习过程而总结的经验分享,因个人知识面有限,如有错误之处,希望您能留言斧正)


1、笛卡尔积(cross join)

  谈到多表连接,我们先引入一个概念,当我们多表连接查询时,没有指定筛选条件或者连接条件时,就会得到笛卡尔积,它是一个数学概念,在数据库中一般又称为交叉连接。
  例如:select * from TABLE_1,TABLE_2;
  当TABLE_1中有4行数据,TABLE_2中有2行数据,笛卡尔积结果则是TABLE_1表每一行和TABLE_2表每一行相结合而形成的结果集,总共4*2=8行数据。
在这里插入图片描述

  可想而知如果两个表的数据都过千上万,结果集很容易达到百万以上级别,这其实是一个不容忽视的结果,笛卡尔积可以说是最基本的连接查询,但实际情况下我们并不会想让它直接出现。

附:TABLE_1和TABLE_2的数据建立语句,后面会使用这两个表数据做例子:

CREATE TABLE "SYSDBA"."TABLE_1"
(
"ID" INTEGER,
"UNAME" VARCHAR(50),
"CITY" VARCHAR(50),
"SID" INTEGER) ;
insert into "SYSDBA"."TABLE_1" ("ID","UNAME","CITY","SID") values (1001, '清华大学', '北京', 23001);
insert into "SYSDBA"."TABLE_1" ("ID","UNAME","CITY","SID") values (1002, '北京大学', '北京', null);
insert into "SYSDBA"."TABLE_1" ("ID","UNAME","CITY","SID") values (1003, '中国科学技术大学', '安徽', 23002);
insert into "SYSDBA"."TABLE_1" ("ID","UNAME","CITY","SID") values (1004, '上海交通大学', '上海', null);
COMMIT;
CREATE TABLE "SYSDBA"."TABLE_2"
(
"ID" CHAR(10),
"SNAME" VARCHAR(50),
"AGE" VARCHAR(50));
insert into "SYSDBA"."TABLE_2" ("ID","SNAME","AGE") values ('23001     ', '李宁', '18');
insert into "SYSDBA"."TABLE_2" ("ID","SNAME","AGE") values ('23002     ', '刘明', '18');
COMMIT;

2、连接的方式

  广义看主要可分为三大类:内连接、外连接和UNION连接。(这里也是按网上收集的资料,参照大多数认可的划分方式,当然按照细类仍可往下细分,又或者从不同的角度去看可以得到不同的划分大类,但这不影响我们的学习)
  其实我们主要理解一点,不同的连接方式会得到不同的查询结果,而连接方式的选择仅仅取决于我们想得到什么样的结果。 所以连接方式的详细准确分类反而显得不是很重要了,当然出于学习目的还是可以简要划分一下。
在这里插入图片描述

2.1内连接(inner join)

  其主要为取出两张表中存在对应关系的数据,连接在一起后输出成结果显示,没有对应关系的数据都不显示。下面将介绍一些比较常见的内连接细分连接方式。
  (后面将使用这两张表TABLE_1和TABLE_2作为例子使用,数据准备SQL语句在第1点尾处有附上)
在这里插入图片描述
在这里插入图片描述

2.1.1 等值连接

  内连接的一种,主要通过等值条件进行连接,如以下写法都为等值连接:

select * from TABLE_1 A, TABLE_2 B 
where A.SID=B.ID;
select * from TABLE_1 A 
inner join TABLE_2 B on A.SID =B.ID;

在这里插入图片描述

2.1.2 不等值连接

  内连接的一种,主要通过不等值条件进行连接,如以下写法都为不等值连接:

select * from TABLE_1 A, TABLE_2 B 
where A.SID > B.ID;
select * from TABLE_1 A 
inner join TABLE_2 B on A.SID >B.ID;

在这里插入图片描述

2.1.3 自然连接

  它是特殊的等值连接,特殊之处有两个:

  1. 它不需要指定比较的属性,它会自动比较两个表的同名同域属性(列),只有这些属性对应的值均相等,元组才会被从两个表中选择出来进行连接;
  2. 二是它能够删除连接结果中的重复属性列。
    如以下写法都为自然连接:

在达梦中存在两种自然连接的写法,他们稍有不同,在这里再构造一个表TABLE_3和上面的TABLE_1来演示一下区别

CREATE TABLE "SYSDBA"."TABLE_3"
(
"ID" VARCHAR(50),
"SID" INTEGER,
"RANK" VARCHAR(50));
insert into "SYSDBA"."TABLE_3" ("ID","SID","RANK") values ('1001', 23001, '大学一年级');
insert into "SYSDBA"."TABLE_3" ("ID","SID","RANK") values ('1003', 23004, '大学二年级');
insert into "SYSDBA"."TABLE_3" ("ID","SID","RANK") values ('1001', 23005, '大学二年级');
COMMIT;

两表数据如下,我们构造的TABLE_3和TABLE_1存在两个列ID和SID是同名列,但是ID列一个是INT类型,一个是VARCHAR类型
在这里插入图片描述

写法一:TABLE_1表做前驱表自然连接TABLE_3

select * from TABLE_1 A natural join TABLE_3 C;

从结果图可以看出来,这种写法是把TABLE_1和TABLE_3所有同名列作为连接条件,即列ID和SID在两个表中对应的值同时相等时,才取结果。并且ID列类型不同时,取前驱表的ID列类型INT。
在这里插入图片描述
当我们把TABLE_3作为前驱表时:ID列类型也变成了TABLE_3的VARCHAR
在这里插入图片描述

写法二:连接过程,指定使用同名列

select * from TABLE_1 A join TABLE_3 B using (ID);

从结果可以看出来,此类写法下,只会使用指定列作为连接条件比较,而没有指定的其他同名列忽略不做比较。即两表的ID列值相等时取结果。
在这里插入图片描述

2.1.4 自连接

  顾名思义,当一个表自己和自己构建的连接查询时,一般称之为自连接。
例如:在学校信息表TABLE_1中查询和清华大学在同一个城市的所有大学。

select B.ID,B.UNAME,B.CITY,B.SID from TABLE_1 A ,TABLE_1 B 
where A.UNAME='清华大学' and A.CITY=B.CITY;

在这里插入图片描述

2.1.5 思考:连接查询中一定要使用表别名吗?

  答案其实在自连接的学习中也可以得出,在某些场景下比如存在同名列时,如果不使用别名去区分开来,那么数据库解释器会无法得知你需要查询的是哪个表的列。
例如:TABLE_1和TABLE_2表中同时存在ID列时,查询ID列没有加上表别名:
在这里插入图片描述
  当然实际书写SQL语句时,我们也是建议使用具备特征性的别名的,一个是增加SQL语句的可读性,一个就是区分表的列字段了(特别是较复杂的SQL语句中,如果编写者没有使用表别名,那么对于后读者来说,梳理整个表列关系就很让人头痛了)

2.2 外连接(outer join)

  其主要以其中一个表作为内表,其中所有数据全部展示,再以其他表作为外表,外表符合内表条件,存在对应关系的数据连接内表以悬浮的形式展示,而没有和内表该行数据存在对应关系的,则以NULL填充。
为方便后面例子演示,我们先把TABLE_1的数据做一下改动

update TABLE_1 A set A.ID='23002' WHERE ID='1004'; 
COMMIT;

2.2.1 左外连接(left join)

  可以说是经常使用到的连接方式,以左表为基表,右表符合条件的在右侧悬浮连接,如果没有符合条件的则以NULL填充。
例如写法一:是比较常见的写法

select * from TABLE_1 A 
left join TABLE_2 B on A.SID=B.ID;

在这里插入图片描述
写法二:区别于写法一的left join ,是以where 和匹配表的列条件后加上"(+)"的形式,写法一和写法二的查询结果是一样的。

select * from TABLE_1 A,TABLE_2 B 
where A.SID=B.ID(+);

在这里插入图片描述

2.2.2 右外连接(right join)

  和左外连接相反,以右表为基表,左表符合条件的在左侧悬浮连接,如果没有符合条件的则以NULL填充。
例如写法一:

select * from TABLE_1 A 
right join TABLE_2 B on A.ID=B.ID;

在这里插入图片描述
写法二:结果和写法一也是一致的。

select * from TABLE_1 A,TABLE_2 B 
where A.ID(+)=B.ID;

在这里插入图片描述

2.2.3 全外连接(full join)

  它是左外连接和右外连接的结合。左右表中,相对于另一表的行数据没有符合条件的行数据时,使用NULL填充。
如:

select * from TABLE_1 A 
full join TABLE_2 B on A.ID=B.ID;

在这里插入图片描述

2.2.4 半连接(semi join)

  常见于子查询中,利用另一个表构造条件列,来查询内表数据,也分左右半连接。左半连接和左外连接的区别是,右表仅作为连接的条件表,用于筛选左表数据,查询结果不包含右表数据。右半连接相似。
例如:

select B.* from TABLE_2 B
where B.ID in (select A.SID from TABLE_1 A where A.CITY='北京');

查询结果只有基表TABLE_2符合子表TABLE_1条件筛选的数据。
在这里插入图片描述
在这里插入图片描述

2.3 UNION

  UNION运算符可以将两个或多个查询块的结果集合并为一个结果集输出,它具备以下特点:
1. 每个查询块的查询列数目必须相同;
2. 每个查询块对应的查询列的数据类型必须兼容;
3. 在 UNION 后的可选项关键字ALL的意思是保持所有重复,而没有 ALL 的情况下表示删除所有重复;
4. 在 UNION 后的可选项关键字 DISTINCT 的意思是删除所有重复。缺省值为DISTINCT。
  UNION 和 UNION ALL 的区别是前者会过滤掉值完全相同的元组,为此 UNION 操作符需要建立 HASH 表缓存所有数据并去除重复,当HASH表大小超过了INI参数指定的限制时还会做刷盘(例5)。
  因此如果应用场景并不关心重复元组或者不可能出现重复,那么UNION ALL无疑优于UNION。
例1:查询TABLE_1所有列结果和TABLE_2所有列结果后使用UNION连接,但因为两个查询结果的字段个数是不一样的,所以会提示“个数不匹配”。

select A.* from TABLE_1 A
union 
select B.* from TABLE_2 B;

在这里插入图片描述
例2:查询TABLE_1的ID、SID和TABLE_2的ID、SNAME的结果集使用UNION连接合并成一个结果集,但因为TABLE_1的SID是INT类型,而TABLE_2的SNAME是VARCHAR类型,两个对应字段类型不匹配,所以会提示字符串转换出错。

select A.ID,A.SID from TABLE_1 A
union 
select B.ID,B.SNAME from TABLE_2 B;

在这里插入图片描述
例3:查询TABLE_1的ID列和TABLE_2的ID列

select A.ID from TABLE_1 A
union 
select B.ID from TABLE_2 B;;

在这里插入图片描述
例4:UNION ALL,可以看出和例3的区别是没有去掉重复值。

select A.ID from TABLE_1 A
union all
select B.ID from TABLE_2 B;

在这里插入图片描述
例5:验证HAGR参数对UNION操作的效率影响。先建立两个测试表,同时写入一部分测试数据。

---建立测试表TEST_BIG和TEST_SMALL
CREATE TABLE TEST_BIG (
BID INT,
BNAME VARCHAR(100)
)
;

CREATE TABLE TEST_SMALL (
SID INT,
SNAME VARCHAR(100)
);

---循环插入TEST_SMALL 50W行,TEST_BIG 100W行。
DECLARE
        SQLSTR VARCHAR;
        SQLSTR2 VARCHAR;
        b int;
BEGIN
        FOR b IN 1..500000 LOOP           
           SQLSTR='INSERT INTO TEST_SMALL VALUES('||b||',''SMALLNAME'||b||''');';
           EXECUTE IMMEDIATE SQLSTR;           
        END LOOP;
        COMMIT;
END;

DECLARE
        SQLSTR VARCHAR;
        SQLSTR2 VARCHAR;
        b int;
BEGIN
        FOR b IN 1..1000000 LOOP
           SQLSTR='INSERT INTO TEST_BIG VALUES('||b||',''SMALLNAME'||b||''');';
           EXECUTE IMMEDIATE SQLSTR;         
        END LOOP;
        COMMIT;
END;

为对比效果明显,我们调整HAGR参数至最小值:

SP_SET_PARA_VALUE(1,'HAGR_BUF_SIZE',2);   
SP_SET_PARA_VALUE(1,'HAGR_BUF_GLOBAL_SIZE',10);
select * from v$dm_ini where para_name in ('HAGR_BUF_GLOBAL_SIZE','HAGR_BUF_SIZE');

在这里插入图片描述
第一次执行union语句,执行耗时在744毫秒:

select * from TEST_BIG
union 
select * from TEST_SMALL;

在这里插入图片描述

调大HAGR参数:

SP_SET_PARA_VALUE(1,'HAGR_BUF_GLOBAL_SIZE',5000);
SP_SET_PARA_VALUE(1,'HAGR_BUF_SIZE',2000);
select * from v$dm_ini where para_name in ('HAGR_BUF_GLOBAL_SIZE','HAGR_BUF_SIZE');

在这里插入图片描述

然后再次执行union语句,可以看到执行耗时缩短至435毫秒了,可以看到参数的影响在我们日常使用中是不可忽视的,如果内存充足的情况下,调大HAGR参数会对存在HAGR、DIST、集合操作、SPL2、NTTS2 以及HTAB 操作符的语句效率有不错的效果。
在这里插入图片描述

3、达梦数据库多表连接算法

  在上面第2大点,我们已经简要介绍了各种细分的连接方式了,那么这里要提到的连接算法又是什么呢?它和连接方式有什么关系?(如果不想看这段废话,那么可以跳过看后面定论)
  很好理解,我们来举个例子,比如说我们要去旅游,那么第一步就是确定要去哪里旅游呢?北京、四川、云南、海南等,这里的第一步选择旅游目的地就是连接方式的选择过程,可以看出来,不同的旅游目的地,旅游看到的结果是不同的,北京天安门,四川大熊猫,海南三亚海岸。我想要什么结果,就去哪个地方旅游,比如我们选择了北京,那么第二步就到了我们要选择何种交通方式去北京呢?飞机,火车,大巴等,这里交通方式的选择就是连接算法的选择过程,可以看出来,无论哪种交通方式,最终目的是一样的,只是效率不同而已。显而易见的,我们始终要选择最高效率的连接算法or交通方式,去北京那么飞机就是最好的交通方式。有人会问,那么是不是存在一种一直都是最高效率的连接算法呢,那答案肯定是否定的,算法的选择要结合实际场景,比如你的目的地是去本市的小吃街,那总不会也坐飞机去吧!
  我们可以先笼统地下一个定论:
  算法不影响最终结果,它针对的仅仅是连接的过程。
那么到这里,我们就可以结合连接方式的要点,认识连接方式和连接算法之间的关系了,即连接方式影响结果,连接算法针对过程。 显而易见连接算法经常和我们的优化分析息息相关。
  达梦中主要有三种连接算法:嵌套循环连接,归并排序连接,哈希连接。

为了下面的学习例子,先准备两个测试表TEST_SMALL(A表,数据从1到10000)和TEST_BIG(B表,数据从1到100000)建表语句如下(注意,我后面例子都是放在了QWE模式,查询语句所以带上了QWE模式前缀):

CREATE TABLE TEST_BIG (
BID INT,
BNAME VARCHAR(100)
)
;
CREATE TABLE TEST_SMALL (
SID INT,
SNAME VARCHAR(100)
);
----往TEST_SMALL表插入10000行数据
DECLARE
        SQLSTR VARCHAR;
        SQLSTR2 VARCHAR;
        b int;
BEGIN
        FOR b IN 1..10000 LOOP         
           SQLSTR='INSERT INTO TEST_SMALL VALUES('||b||',''SMALLNAME'||b||''');';
           EXECUTE IMMEDIATE SQLSTR;
        END LOOP;
        COMMIT;
END;
----往TEST_BIG表插入100000行数据
DECLARE
        SQLSTR VARCHAR;
        SQLSTR2 VARCHAR;
        b int;
BEGIN
        FOR b IN 1..100000 LOOP
           SQLSTR='INSERT INTO TEST_BIG VALUES('||b||',''BIGNAME'||b||''');';
           EXECUTE IMMEDIATE SQLSTR;           
        END LOOP;
        COMMIT;
END;

在这里插入图片描述

3.1 嵌套循环连接(NEST LOOP)

  最基础的连接算法,将一张表(驱动表)的每一个值与另一张表(被驱动表)的所有值拼接,形成一个大结果集(笛卡尔积的过程) ,再从大结果集中过滤出满足条件的行。驱动表的行数就是循环的次数,将在很大程度上影响执行效率。连接列是否有索引,都可以走NESTLOOP,但没有索引,执行效率会很差,适用场景:
1、驱动表有很好的过滤条件;
2、表连接条件能使用索引;
3、结果集比较小。

例1,当A表和B表连接查询,B表存在较好的过滤条件时:
在这里插入图片描述
例2,当A表和B表连接查询,连接条件都可以使用索引时:
在这里插入图片描述

思考:嵌套循环连接有索引和无索引的情况下,差别会很大吗?

  答案是肯定的,我们来构建个场景,同样还是用上面建立的测试表TEST_BIG 和TEST_SMALL ,不过我们把数据量加上去,TEST_BIG 加到100W,TEST_SMALL 50W。
第一次执行语句:

select * from "QWE"."TEST_SMALL" A,"QWE"."TEST_BIG" B WHERE
A.SID<B.BID and B.BID<200;

  从下图的执行计划看,以B表筛选条件后作为驱动表,嵌套循环连接A表,表扫描都为全表扫描方式,执行耗时在431ms,好像并不慢?
在这里插入图片描述

  我们在A表和B表的连接条件列都加上索引:

CREATE INDEX IDX_TEST_SMALL_SID ON "QWE"."TEST_SMALL" (SID);
CREATE INDEX IDX_TEST_BIG_BID ON "QWE"."TEST_BIG" (BID);

在这里插入图片描述

  然后再次执行我们的例子语句,走索引扫描了,执行耗时也来到了15ms,比没有索引的时候好上很多,但是你可能会有疑问,都是几百毫秒以下,应用没有感知的吧?
在这里插入图片描述

并发测试

  其实不然,我们上Jmeter,线程配置如下,50线程,循环3次,不算激进的场景:
在这里插入图片描述

  无索引的情况下,语句测试情况:除开前期每个线程连接数据库时需要耗时13s左右,后续的平均语句执行时间基本在5.8s左右了!!
在这里插入图片描述

  而有索引的情况下呢:除开前期每个线程连接数据库时需要耗时8s左右,后续的平均语句执行时间基本在220ms左右!!差别已经很明显了吧。
在这里插入图片描述

  其实在数据量更大,并发更多的场景下,这个差距会更加的明显,没有索引的情况下,甚至出现一个语句拖累整个数据库的现象!!
  我们进行一个总结,即嵌套循环连接,有索引和没有索引的情况下,特别是在并发场景,他们的执行效率是存在巨大差异的,所以我们一般都是建议嵌套循环连接使用索引,当然具体情况具体分析。

3.2 归并排序连接(MERGE JOIN)

  两张表的连接列均为索引列,则可以按照索引顺序进行归并,一趟归并就可以找出满足条件的记录。如果查询列也属于索引列的子集,则归并连接只需扫描索引,会有更好的性能表现。在两表连接条件不是等值(如<,<=,>,>=)情况下时,归并排序连接很有用。(归并排序连接需要满足的条件相对于其他两种算法较难,所以并不常见)
在这里插入图片描述

3.3 哈希连接(HASH JOIN)

  哈希连接是在没有索引或索引无法使用情况下大多数连接的处理方式。哈希连接使用关联列去重后结果集较小的表做成HASH表,另一张表的连接列在HASH后向HASH表进行匹配,这种情况下匹配速度极快,主要开销在于对连接表的全表扫描以及 HASH 运算。
  哈希连接比较消耗内存如果系统有很多这种连接时,需调整以下 3 个参数:
1、HJ_BUF_GLOBAL_SIZE----HASH连接操作符的数据总缓存大小(>=HJ_BUF_SIZE),系统级参数,以兆为单位。有效值范围(10~500000)
2、HJ_BUF_SIZE----单个哈希连接操作符的数据总缓存大小,以兆为单位。有效值范围(2~100000)
3、HJ_BLK_SIZE-----哈希连接操作符每次分配缓存 (BLK) 大小,以兆为单位,必须小于HJ_BUF_SIZE。有效值范围(1~50)
在这里插入图片描述

4 连接查询的效率影响

  从上面的介绍,我们可以简单了解三种算法的特点和常见适用场景,接下来我们就更进一步,去了解影响连接查询效率的因素,主要也是三个方面:

  1. 访问路径:对于每张表采用何种方式来获取数据。例如:全表扫描、索引扫描等。查询优化器会估算每种扫描方式的代价,选择代价较小的访问路径。 (注意,索引扫描并不一定就是代价最小的,因为在过滤条件不好的情况下,索引扫描没有覆盖所有列,存在回表时,代价往往是比全表扫描更大的,索引的使用也建议读者深入学习一下,这里不再详细展开)

  2. 连接算法的选择:确定两张表之间采用哪种连接算法。例如:哈希连接、嵌套连接、归并连接。 初始学习,我们可以先笼统地记忆,一般情况下,等值连接条件、没有索引的情况会选择哈希连接;非等值连接条件、有索引筛选条件很好的情况会采用嵌套连接;连接列均为索引列,且需要排序对比时,会采用归并连接。

  3. 连接顺序:当超过2张表进行连接时,就需要考虑表之间的连接顺序。不合适的连接顺序对执行效率有较大影响。一般原则是,经过连接可以产生较小结果集的表优先处理。

4.1 通过例子简单模拟一下连接查询效率的影响因素

例子仍是A表和B表
在这里插入图片描述

4.2 例子1

(这里的QWE是模式,因为我使用的SYSDBA用户跨模式查询所以需要带上):

select * from "QWE"."TEST_SMALL" A,"TEST_BIG" B 
WHERE A.SID>B.BID AND A.SID<100;

分析1:A表存在非常好的过滤条件,中间结果集较小,所以优化器选择了A表做驱动表,使用嵌套循环连接算法完成连接查询。
在这里插入图片描述

验证2:当我们通过Hint强制以B表大表作为驱动表时,可以看到,执行耗时来到了76毫秒,比上面以A表作为驱动表时多了24毫秒左右。(当数据量越大时,这个差距会更加明显)
在这里插入图片描述

验证3:当我们同时在A表和B表的连接列,建立索引时,A表作为驱动表,且过滤条件很好,连接列也都存在索引,这满足了嵌套循环连接的最优条件,所以执行耗时来到了5毫秒,也是这个语句执行计划的可能最优解。
在这里插入图片描述

4.2 例子2

在这里,我们先把A表的数据量提升到30000,B表数据量仍然100000不变

select 
count(*) 
from QWE.TEST_BIG B 
WHERE 
EXISTS 
(SELECT 1 FROM QWE.TEST_SMALL A WHERE A.SID>200 AND A.SID=B.BID)
AND B.BID <>0
LIMIT 1;

分析:执行计划看以A表作为驱动表,进行嵌套循环连接,并通过索引全扫描A表,执行耗时73毫秒,好像没有什么问题,但果真如此吗?在上面我们学习到,嵌套循环连接适用场景是过滤条件比较好的情况下,而我们已知A表在A.SID>200的条件下,可以说是几乎没有过滤性,连接条件也是等值连接,显然更符合哈希连接算法的使用场景,我们测试一下。
在这里插入图片描述
验证1:通过hint 强制走哈希连接时,执行耗时来到了6毫秒,显然我们猜测是准确的,过滤条件不好,且等值连接的情况下,其实更适合哈希连接。
在这里插入图片描述
思考2:HASH连接效率明显较好,是什么影响了优化器没有选择HASH连接,而选择了NEST LOOP,从语句本身分析,语句写法也存在问题,limit 条件明显不需要。
在这里插入图片描述
思考3:语句无法修改的情况下,优化器如何按照最高效率的连接方式。
(其他参数的影响)
在这里插入图片描述
LIMIT的写法受到了TOP_DIS_HASH_FLAG参数的影响,当指定值为0时即可解决问题。
TOP_DIS_HASH_FLAG:默认值1,动态,是否通过禁用HASH JOIN方式来优化TOP查询,取值
0:不优化;
1:当OPTIMIZER_MODE为0时,TOP下方连接禁用HASH JOIN;当OPTIMIZER_MODE为1时,TOP下方最近的连接倾向于不使用 HASH JOIN;
2:当OPTIMIZER_MODE为0时,TOP下方连接禁用HASH JOIN;当OPTIMIZER_MODE为1时,TOP下方所有连接都倾向于不使用HASH JOIN

5 总结

  连接查询可以说是关系数据库非常常见的查询场景,深入了解各个连接查询的方式和算法的特点,有助于我们更好地和关系数据库打交道。而从访问路径、连接顺序、连接算法三个方面去思考,基本可以解决大部分连接查询可能存在的效率问题。

  • 0
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值