从多表连接后的select count(*)看待SQL优化
从多表连接后的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优化的更多相关文章
- 数据库多表连接方式介绍-HASH-JOIN
1.概述 hash join是一种数据库在进行多表连接时的处理算法,对于多表连接还有两种比较常用的方式:sort merge-join 和 nested loop. 为了比较清楚的介绍hash joi ...
- Oracle多表连接,提高效率,性能优化 (转)
执行路径:ORACLE的这个功能大大地提高了SQL的执行性能并节省了内存的使用:我们发现,单表数据的统计比多表统计的速度完全是两个概念.单表统计可能只要0.02秒,但是2张表联合统计就可能要几十表了. ...
- PostgreSQL EXPLAIN执行计划学习--多表连接几种Join方式比较
转了一部分.稍后再修改. 三种多表Join的算法: 一. NESTED LOOP: 对于被连接的数据子集较小的情况,嵌套循环连接是个较好的选择.在嵌套循环中,内表被外表驱动,外表返回的每一行都要在内表 ...
- Oracle多表连接效率,性能优化
Oracle多表连接,提高效率,性能优化 (转) 执行路径:ORACLE的这个功能大大地提高了SQL的执行性能并节省了内存的使用:我们发现,单表数据的统计比多表统计的速度完全是两个概念.单表统计可能只 ...
- SqlServer 多表连接、聚合函数、模糊查询、分组查询应用总结(回归基础)
--exists 结合 if else 以及 where 条件来使用判断是否有数据满足条件 select * from Class where Name like '%[1-3]班' if (not ...
- Access数据库多表连接查询
第一次在Access中写多表查询,就按照MS数据库中的写法,结果报语法错,原来Access的多表连接查询是不一样的 表A.B.C,A关联B,B关联C,均用ID键关联 一般写法:select * fro ...
- SQLSERVER 里SELECT COUNT(1) 和SELECT COUNT(*)哪个性能好?
SQLSERVER 里SELECT COUNT(1) 和SELECT COUNT(*)哪个性能好? 今天遇到某人在我以前写的一篇文章里问到 如果统计信息没来得及更新的话,那岂不是统计出来的数据时错误的 ...
- Oracle表连接
一个普通的语句select * from t1, t2 where t1.id = t2.id and t1.name = 'a'; 这个语句在什么情况下最高效? 表连接分类: 1. 嵌套循环连接(N ...
- select count(*)和select count(1)的区别 (转)
A 一般情况下,Select Count (*)和Select Count(1)两着返回结果是一样的 假如表沒有主键(Primary key), 那么count(1)比count(*)快, 如果有主键 ...
随机推荐
- bzoj 4903: [Ctsc2017]吉夫特【lucas+状压dp】
首先根据lucas, \[ C_n^m\%2=C_{n\%2}^{m\%2}*C_{n/2}^{m/2} \] 让这个式子的结果为计数的情况只有n&m==m,因为m的每一个为1的二进制位都需要 ...
- 洛谷 P3960 列队【线段树】
用动态开点线段树分别维护每一行和最后一列,线段树的作用是记录被选的点的个数以及查询第k个没被选的点,每次修改,从行里标记被选的点,从最后一列标记向左看齐之后少的点,然后用vector维护行列的新增点 ...
- touch的基本用法
touch的基本功能是改变文件的时间戳,以下是三种常用用法: 1.创建一个空文件 以当前时间为时间戳创建一个空文件.$ touch touch.txt //touch.txt不存在 2.更改文件时间戳 ...
- javascript E5面向对象和 E6面向对象
javascript es6之前的面向对象方法: 一般使用构造函数来实现 function Person (name, age) { this.name = name; this.age = age; ...
- LightOj 1088 - Points in Segments (二分枚举)
题目链接: http://www.lightoj.com/volume_showproblem.php?problem=1088 题目描述: 给出一个n位数升序排列的数列,然后q个查询,每个查询问指定 ...
- [WOJ2549]逻辑的连通性
题目描述: 数学中,假如有命题 p 一定能推出命题 q,则称 p 是 q 的充分条件,q 是 p 的必要 条件. 特别的,当 p 既是 q 的充分条件,又是 q 的必要条件时,称 p 和 q 互为 充 ...
- Android课程设计第五天欢迎界面(滑动)和图形选择
注意:课程设计只为完成任务,不做细节描述~ 滑动界面 package com.example.myapplication; import android.content.Intent; import ...
- A Refining Company LightOJ - 1036
A Refining Company LightOJ - 1036 描述好长啊... 题意:在m*n的矩阵上,每一格摆一个向上或者向左的传送带(不能同时摆,只能摆一个).同时,每一格有两种物资Uran ...
- linux高负载下mysql数据库彻底优化
同时在线访问量继续增大 对于1G内存的服务器明显感觉到吃力严重时甚至每天都会死机 或者时不时的服务器卡一下 这个问题曾经困扰了我半个多月MySQL使用是很具伸缩性的算法,因此你通常能用很少的内存运行或 ...
- this关键字实现串联构造函数调用
在一个类中如果需要实现多个自定义构造函数,通常做法是在构造函数中实现各自的业务逻辑,如果这些业务逻辑的实现并非截然不同的话,显然不符合oop编程思想,极不利于维护,当然,我们也可以通过将相同的逻辑部分 ...