Mysql内链接、左链接会出现笛卡尔积的理解

先简单解释一下笛卡尔积。java

如今,咱们有两个集合A和B。mysql

A = {0,1}     B = {2,3,4}算法

集合 A×B 和 B×A的结果集就能够分别表示为如下这种形式:sql

A×B = {(0,2),(1,2),(0,3),(1,3),(0,4),(1,4)};数据库

B×A = {(2,0),(2,1),(3,0),(3,1),(4,0),(4,1)};学习

以上A×B和B×A的结果就能够叫作两个集合相乘的‘笛卡尔积’。优化

从以上的数据分析咱们能够得出如下两点结论:spa

1,两个集合相乘,不知足交换率,既 A×B ≠ B×A;3d

2,A集合和B集合相乘,包含了集合A中元素和集合B中元素相结合的全部的可能性。既两个集合相乘获得的新集合的元素个数是 A集合的元素个数 × B集合的元素个数;code

MySQL的多表查询(笛卡尔积原理)

  1. 先肯定数据要用到哪些表。
  2. 将多个表先经过笛卡尔积变成一个表。
  3. 而后去除不符合逻辑的数据(根据两个表的关系去掉)。
  4. 最后当作是一个虚拟表同样来加上条件便可。

数据库表链接数据行匹配时所遵循的算法就是以上提到的笛卡尔积,表与表之间的链接能够当作是在作乘法运算。

好比如今数据库中有两张表,student表和 student_subject表,以下所示:

  

咱们执行如下的sql语句,只是纯粹的进行表链接。

SELECT * from student JOIN student_subject;
SELECT * from student_subject JOIN student;

看一下执行结果:

  

  表1.0                            表1.1

从执行结果上来看,结果符合咱们以上提出的两点结论(红线标注部分);

以第一条sql语句为例咱们来看一下他的执行流程,

1,from语句把student表 和 student_subject表从数据库文件加载到内存中。

2,join语句至关于对两张表作了乘法运算,把student表中的每一行记录按照顺序和student_subject表中记录依次匹配。

3,匹配完成后,咱们获得了一张有 (student中记录数 × student_subject表中记录数)条的临时表。 在内存中造成的临时表如表1.0所示。咱们又把内存中表1.0所示的表称为‘笛卡尔积表’。

 

  针对以上的理论,咱们提出一个问题,难道表链接的时候都要先造成一张笛卡尔积表吗,若是两张表的数据量都比较大的话,那样就会占用很大的内存空间这显然是不合理的。因此,咱们在进行表链接查询的时候通常都会使用JOIN xxx ON xxx的语法,ON语句的执行是在JOIN语句以前的,也就是说两张表数据行之间进行匹配的时候,会先判断数据行是否符合ON语句后面的条件,再决定是否JOIN。

  所以,有一个显而易见的SQL优化的方案是,当两张表的数据量比较大,又须要链接查询时,应该使用 FROM table1 JOIN table2 ON xxx的语法,避免使用 FROM table1,table2 WHERE xxx 的语法,由于后者会在内存中先生成一张数据量比较大的笛卡尔积表,增长了内存的开销。

下面引出Mysql的左右链接和内链接的笛卡尔积...

 一个同事跟我讨论左链接查询,是否是笛卡尔积。我第一反应,左链接确定不是笛卡尔积啊,左链接是以左表为准,左表有m条记录,则结果集是m条记录(哈哈,若是是你,你是否是也是这样的反映),同事听了,说内链接会是笛卡尔积。在数据库里试验了一下,发现,事实比想象中要复杂。

首先说下结论:连接查询,若是on条件是非惟一字段,会出现笛卡尔积(局部笛卡尔积);若是on条件是表的惟一字段,则不会出现笛卡尔积。

  下面是具体的试验:(以真三国无双v3.9d蜀国阵容为例...)

  文中会有两张表,user表和job表,表数据以下,其中user为5条记录,job为4条记录

USER:    job:  

 

1.交叉链接

若是A表有m(5)条记录,m1条符合on条件,B表有n(4)条记录,有n1条符合on条件,无条件交叉链接的结果为: m*n=5*4=20

SELECT * FROM `user` CROSS JOIN job;  

这种等同于(交叉查询等于不加on的内链接)

SELECT * FROM `user` , job;

sql执行结果:总共20条记录

  结论:交叉链接,会产生笛卡尔积。

2.内链接(能够当作左链接的特殊状况,只保留符合主表中on条件的记录)
(1)内链接惟一字段

若是A表有m(5)条记录,m1(4)条符合on条件,B表有n(4)条记录,有n1(3)条符合on条件,内链接惟一字段结果为:Max(m1,n1)=4

1,2,2,6,7 和 1,2,7,8对比,以user表为主表,由于主表中有4条符合条件的记录(1,2,2,7),而job表有3条符合条件的记录(1,2,7),取二者中的最大的,因此为4条

SELECT * FROM `user` u JOIN job j ON u.JOB_ID=j.ID;

sql执行结果为:4条记录


  结论:假如,内链接查询,on条件是A表或者B表的惟一字段,则结果集是两表的交集,不是笛卡尔积。

 

(2)内链接非惟一字段
若是A表有m(5)条记录,m1(2)条符合on条件,B表有n(4)条记录,有n1(3)条符合on条件,则结果集是Max(m1,n1)=3条

1,2,2,6,7 和 1,1,7,8对比,以user表为主表,由于主表中有2条符合条件的记录(1,7),而job表有3条符合条件的记录(1,1,7),取二者中的最大的,因此为3

SELECT * FROM `user` u JOIN job j ON u.valid=j.valid;


  结论:假如,on条件是表中非惟一字段,则结果集是两表匹配到的结果集的笛卡尔积(局部笛卡尔积) 。

3.外链接
(1)左链接
    a.左链接惟一字段
假如A表有m(5)条记录,B表有n(4)条记录,则结果集是m=5

1,2,2,6,7 和 1,2,7,8对比,以user表为主表,由于主表中有4条符合条件的记录(1,2,2,7),而job表有3条符合条件的记录(1,2,7),取二者中的最大的,因此取4条,而后再加上user表中没有在job表中找到对应关系的记录(即对应的job表都为null,5-4=1),因此最终结果为4+1=5

SELECT * FROM USER u LEFT JOIN job j ON u.JOB_ID=j.id;

SQL查询结果:5条记录

结论:on条件是惟一字段,则结果集是左表记录的数量。

b.左链接非惟一字段
1,2,2,6,7 和 1,1,7,8对比,以user表为主表,由于主表中有2条符合条件的记录(1,7),而job表有3条符合条件的记录(1,1,7),取二者中的最大的,因此取3条,而后在加上user表在job表中没有匹配的记录(即对应的job表都为null,为5-2=3),因此最终结果为3+3=6

SELECT * FROM `user` u LEFT JOIN job j ON u.VALID=j.VALID;


  结论:左链接非惟一字段,是局部笛卡尔积。

 

c.当on 条件为假时的内链接:

SELECT * FROM `user` u LEFT JOIN job j ON 0;

sql查询结果:5条

结论:当on条件为假的时候,即user在job表中一条符合记录的都没有,那么即为:user表中的全部记录条数,因此为5条,job表中的值都为null

(2)右链接
  同左链接,这里就不赘述了

全外链接
  mysql不支持

总结:左右链接是否产生笛卡尔积,和on的条件是否为惟一索引没有关系,只和左表、右表二者各自匹配on条件的记录条数有关系(左链接和右链接能够这么作:1:由INNER JOIN查询全匹配记录;2:查询左表或者右表没有符合on条件的记录;3.全匹配记录+没有匹配上的记录就是左链接或者右链接查询的结果集)

1.全匹配:

不管哪一种查询,首先计算出on匹配记录(FROM user INNER JOIN job ON ...或者使用 FROM user,job where...),匹配记录的查询结果为:若A表有m条记录,符合on查询条件的为m1条,B表有n条记录,符合on条件的为n1条,那么匹配记录为MAX(m1,n1);

2.左链接:

结果集为:MAX(m1,n1)+(m-m1);

若是m1 > n1,则不会产生笛卡尔积,由于不管不匹配的记录(m-m1),仍是匹配的记录MAX(m1,n1),都是从左表中取记录,因此不会出现重复的记录;反之,若是m1 < n1,则必定会产生笛卡尔积,由于MAX(m1,n1)是从右表中取的,而根据笛卡尔积的原理,右表中的每条记录都会和左表中的全部记录匹配一次,因此符合on条件的n1条记录也必定会和左表中的全部记录都匹配一次,而左表中符合记录只有m1条,因此形成笛卡尔积的条数为(n1-m1)条

即用内链接的记录(MAX(m1,n1)),加上左表没有知足on条件的记录(m-m1),因此为:MAX(m1,n1)+(m-m1);

3.有链接

结果集为:MAX(m1,n1)+(n-n1);

若是m1 < n1,则不会产生笛卡尔积,由于不管不匹配的记录(n-n1),仍是匹配的记录MAX(m1,n1),都是从右表中取记录,因此不会出现重复的记录;反之,若是m1 > n1,则必定会产生笛卡尔积,由于MAX(m1,n1)是从左表中取的,因此形成笛卡尔积的记录条数为(m1-n1)条

即用内链接的记录(MAX(m1,n1)),加上右表没有知足on条件的记录(n-n1),因此为:MAX(m1,n1)+(n-n1);

下面再来谈下:

Mysql:ON 与 WHERE 的区别

不少同窗在学习 Mysql 表关联的时候弄不清 ONWHERE 的区别,不知道条件应该写在 ON 里面仍是 WHERE 里面,做者在工做的时候也入过坑,总以为条件写在哪里查询结果都是同样的,最后出错坏了事,差点惹了大祸。因此今天简单易懂的总结一下他们的区别,你们共同窗习。

准备工做

咱们先准备两个表,并造一些数据:

表t1:

CREATE TABLE `t1` (
  `id` BIGINT(20) NOT NULL DEFAULT '0' COMMENT '主键id',
  `name` CHAR(100) NOT NULL DEFAULT '' COMMENT '姓名',
  `age` INT(11) NOT NULL DEFAULT '0'
) ENGINE=INNODB DEFAULT CHARSET=utf8;

INSERT  INTO `t1`(`id`,`name`,`age`) VALUES (1,'C罗',33),(2,'梅西',31),(3,'内马尔',29);

表t2:

CREATE TABLE `t2` (
  `id` BIGINT(20) NOT NULL DEFAULT '0' COMMENT '主键id',
  `goals` INT(11) NOT NULL DEFAULT '0' COMMENT '进球数',
  `matches` INT(11) NOT NULL DEFAULT '0' COMMENT '比赛编号'
) ENGINE=INNODB DEFAULT CHARSET=utf8;


INSERT  INTO `t2`(`id`,`goals`,`matches`) VALUES (1,3,1),(1,5,2),(2,0,1),(2,8,2);

查询结果如图:

表t1记录:

表t2记录:

探究

口诀:先执行 ON,后执行 WHEREON 是创建关联关系,WHERE 是对关联关系的筛选

记住这句话就能够准确地判断查询结果了,咱们经过两个 sql 来进行分析:

SQL1:

SELECT t1.id,t2.id,t1.name,t1.age,t2.`matches` FROM t1 LEFT JOIN t2 ON t1.id = t2.id WHERE matches = 2; -- 条件放在 WHERE

前提是 LEFT JOIN,因此左边的数据在建立关联关系时会保留,根据口诀,先执行 ON 创建关联关系,造成子表,最后在子表中经过 WHERE 筛选,过程以下:

左表符合记录的t1.id = t2.id的记录有2条,右表符合记录的有4条,因此MAX(m1,n1)为4条,其中左表没有符合on条件的记录为(3-2=1)条,因此LEFT JOIN的结果总共有5条,最后一条左表没有匹配上右表记录,因此右表的属性都为null,以下:

可是最终结果从5条记录中再经过where进行筛选,即matches为2,因此结果只有2条(注意先LEFT JOIN,而后再是where,因此此时5条记录中不符合where条件的记录会被排除,即最终的结果再也不是左表全部的记录):

 

SQL2:

SELECT t1.id,t2.id,t1.name,t1.age,t2.`matches` FROM t1 LEFT JOIN t2 ON t1.id = t2.id AND matches = 2; -- 条件放在 ON

SQL2没有 WHERE,那么 ON 创建的关联关系就是最终结果(由于没有where条件进行最终筛选,全部最终结果为内联记录加上左表中没有符合on条件的记录):

符合ON条件的记录,改成内联INNER JOIN ,查询基础数据:MAX(m1,n1)

SELECT t1.id,t2.id,t1.name,t1.age,t2.`matches` FROM t1 INNER JOIN t2 ON t1.id = t2.id AND matches = 2;

因此MAX(m1,n1)为2条,结果为:

再由基础数据加上左表没有匹配上的记录数(只有id为3的没有匹配上,即(n-n1) = 1)只有1条,因此最终结果为:

最终结果为:MAX(m1,n1)+(m-m1) = 2 + (id为3的记录) = 3条

经过这两个 sql 能够很好的区分 WHEREON 的区别了,但愿你们使用的时候多注意这一点,避免犯错!

相关文章
相关标签/搜索