从多表连接后的select count(*)看待SQL优化

一朋友问我,以下这SQL能直接改写成select count(*) from a吗?

SELECT COUNT(*)
FROM a
LEFT JOIN b ON a.a1 = b.b1
LEFT JOIN c ON b.b1 = c.c1

废话不多说,直接上实验。

1. 准备数据

创建测试表a,b,c,并插入数据,a有重复数据,b是唯一数据,c是唯一数据,d有重复数据。

1) 创建a表
create table a (a1 int);
insert into a select 1;
insert into a select 2;
insert into a select 3;
insert into a select 1;
insert into a select 2;
insert into a select 3;
insert into a values(null);
insert into a values(null);
insert into a values(null);
insert into a values(null);
2)创建b表
create table b (b1 int);
insert into b select 1;
insert into b select 2;
insert into b select 3;
insert into b select 4;
insert into b select 5;

3)创建c表
create table c (c1 int);
insert into c select 7;
insert into c select 8;
insert into c select 9;
insert into c values(null);
insert into c values(null);

4)创建d表
create table d (d1 int);
insert into d select 1;
insert into d select 1;
insert into d select 1;
insert into d select 1;
insert into d select 1;
insert into d select 1;

2. 数据查看

a表 b表 c表 d表
1 1 7 1
2 2 8 1
3 3 9 1
1 4 null 1
2 5 null 1
3     1
null      
null      
null      
null      

3. SQL示例

3.1 a表连接b表再连接c表(N:1:1的关系)

a表连接列有重复数据,b,c两表的连接列都是唯一数据

SELECT COUNT(*)
FROM a
LEFT JOIN b ON a.a1 = b.b1
LEFT JOIN c ON b.b1 = c.c1 +----------+
| COUNT(*) |
+----------+
| 10 |
+----------+
1 row in set (0.00 sec)
返回的10条数据

此时SQL只返回a表的数据,那么这时候SQL可以改写成

mysql> select count(*) from a;
+----------+
| count(*) |
+----------+
| 10 |
+----------+
1 row in set (0.00 sec)

3.2 b表连接a表再连接c表(1:N:1的关系)

SELECT count(*)
FROM b
LEFT JOIN a ON b.b1 = a.a1
LEFT JOIN c ON a.a1 = c.c1 +----------+
| count(*) |
+----------+
| 8 |
+----------+
1 row in set (0.00 sec)

原本b表是5条数据,left join后变为8条,此时就不能改写成上述形式了,我们来看下,具体数据是什么。

+------+------+------+
| b1 | a1 | c1 |
+------+------+------+
| 1 | 1 | NULL |
| 2 | 2 | NULL |
| 3 | 3 | NULL |
| 1 | 1 | NULL |
| 2 | 2 | NULL |
| 3 | 3 | NULL |
| 4 | NULL | NULL |
| 5 | NULL | NULL |
+------+------+------+
8 rows in set (0.00 sec)

可以看到a表的重复数据,在b表重复展现了,c表与a表连接,没有相等的数据(null不等于null)所以c1列展现都为null值。

这时候此SQL可以等价于以下:

SELECT count(*)
FROM b
LEFT JOIN a ON b.b1 = a.a1; +----------+
| count(*) |
+----------+
| 8 |
+----------+
1 row in set (0.00 sec)

3.3 a表与d表相连接(N:N关系)

SELECT *
FROM a
LEFT JOIN d ON a.a1 =d.d1; +------+------+
| a1 | d1 |
+------+------+
| 1 | 1 |
| 1 | 1 |
| 1 | 1 |
| 1 | 1 |
| 1 | 1 |
| 1 | 1 |
| 1 | 1 |
| 1 | 1 |
| 1 | 1 |
| 1 | 1 |
| 1 | 1 |
| 1 | 1 |
| 2 | NULL |
| 3 | NULL |
| 2 | NULL |
| 3 | NULL |
| NULL | NULL |
| NULL | NULL |
| NULL | NULL |
| NULL | NULL |
+------+------+
20 rows in set (0.00 sec)

可以看a表a1列数据组成是 a表2个1 * b表 6个1 = 12个1,再加上原本a1列的数据8条,总共20条数据。

4. 总结

从以上实验可以延伸到,如果连接列基数很低,此时left join就相当于笛卡儿积。。

所以在做SQL优化时候,尤其需要关注连接列的基数,与表与表之间的关系。

从多表连接后的select count(*)看待SQL优化的更多相关文章

  1. 数据库多表连接方式介绍-HASH-JOIN

    1.概述 hash join是一种数据库在进行多表连接时的处理算法,对于多表连接还有两种比较常用的方式:sort merge-join 和 nested loop. 为了比较清楚的介绍hash joi ...

  2. Oracle多表连接,提高效率,性能优化 (转)

    执行路径:ORACLE的这个功能大大地提高了SQL的执行性能并节省了内存的使用:我们发现,单表数据的统计比多表统计的速度完全是两个概念.单表统计可能只要0.02秒,但是2张表联合统计就可能要几十表了. ...

  3. PostgreSQL EXPLAIN执行计划学习--多表连接几种Join方式比较

    转了一部分.稍后再修改. 三种多表Join的算法: 一. NESTED LOOP: 对于被连接的数据子集较小的情况,嵌套循环连接是个较好的选择.在嵌套循环中,内表被外表驱动,外表返回的每一行都要在内表 ...

  4. Oracle多表连接效率,性能优化

    Oracle多表连接,提高效率,性能优化 (转) 执行路径:ORACLE的这个功能大大地提高了SQL的执行性能并节省了内存的使用:我们发现,单表数据的统计比多表统计的速度完全是两个概念.单表统计可能只 ...

  5. SqlServer 多表连接、聚合函数、模糊查询、分组查询应用总结(回归基础)

    --exists 结合 if else 以及 where 条件来使用判断是否有数据满足条件 select * from Class where Name like '%[1-3]班' if (not ...

  6. Access数据库多表连接查询

    第一次在Access中写多表查询,就按照MS数据库中的写法,结果报语法错,原来Access的多表连接查询是不一样的 表A.B.C,A关联B,B关联C,均用ID键关联 一般写法:select * fro ...

  7. SQLSERVER 里SELECT COUNT(1) 和SELECT COUNT(*)哪个性能好?

    SQLSERVER 里SELECT COUNT(1) 和SELECT COUNT(*)哪个性能好? 今天遇到某人在我以前写的一篇文章里问到 如果统计信息没来得及更新的话,那岂不是统计出来的数据时错误的 ...

  8. Oracle表连接

    一个普通的语句select * from t1, t2 where t1.id = t2.id and t1.name = 'a'; 这个语句在什么情况下最高效? 表连接分类: 1. 嵌套循环连接(N ...

  9. select count(*)和select count(1)的区别 (转)

    A 一般情况下,Select Count (*)和Select Count(1)两着返回结果是一样的 假如表沒有主键(Primary key), 那么count(1)比count(*)快, 如果有主键 ...

随机推荐

  1. android内存溢出 java.lang.OutOfMemoryError

    今天在做ListView 的时候.想做一个音乐列表模块,前面是图片,后面是分类名称,如下图: 结果运行时候,LogCat是总是报 java.lang.OutOfMemoryError的错误,顾名思义, ...

  2. Swift dynamic关键字

    使用dynamic关键字标记属性,使属性启用Objc的动态转发功能: dynamic只用于类,不能用于结构体和枚举,因为它们没有继承机制,而Objc的动态转发就是根据继承关系来实现转发. 参考资料: ...

  3. Hdu 3652 B-number (同余数位DP)

    题目链接: Hdu 3652 B-number 题目描述: 给出一个数n,问 [1, n]区间内有几个数能被13整除并且还有13这个子串? 解题思路: 能整除的数位DP,确定好状态随便搞搞就能过了.d ...

  4. 481 Magical String 魔力字符串

    详见:https://leetcode.com/problems/magical-string/description/ C++: 方法一: class Solution { public: int ...

  5. 167 Two Sum II - Input array is sorted 两数之和 II - 输入有序数组

    给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数.函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2.请注意,返回的下标值(i ...

  6. 使用mysql作为配置文件的地址

    server端配置 POM文件 <dependency> <groupId>org.springframework.boot</groupId> <artif ...

  7. 【转】哪个更快:Java堆还是本地内存

    译文出处: shenzhang   原文出处:原文链接 使用Java的一个好处就是你可以不用亲自来管理内存的分配和释放.当你用new关键字来实例化一个对象时,它所需的内存会自动的在Java堆中分配.堆 ...

  8. Web版简易五子棋

    前些时候把大三写的C++版五子棋改成Web板挂到了网上,具有一定傻瓜式智能,欢迎体验使用拍砖:http://www.zhentiyuan.com/Games/QuickFiveChess.aspx 现 ...

  9. CSS3常用属性浏览器兼容前缀

    1.检测网站https://gsnedders.html5.org/outliner/ 2.查询是否支持前缀http://caniuse.com 3.border-radius\box-shadow\ ...

  10. Scrapy-Redis分布式爬虫小白问题记录

    1.首先我是将Redis装在了阿里云的一台CentOS6.8上,使用ps -ef|grep redis查看是否成功运行 2.CentOS安装scrapy请参考 http://blog.csdn.net ...