从多表连接后的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优化时候,尤其需要关注连接列的基数,与表与表之间的关系。

原文地址:https://www.cnblogs.com/wanbin/p/9569953.html

时间: 2024-10-12 02:19:22

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

浅析表连接

表连接 表连接是一个很有意思的事情,报表中常用的就是JOIN和LEFT JOIN,可能大家也会看到INNER JOIN , LEFT OUTER JOIN等,它们的关系,请读者自己网上查阅,在这里我们要卖个关子. 对初学者来说,表连接是很容易迷糊的一点.容易混淆的原因是因为进行表连接时,经常会把关联字段和关联字段中存的数据混在一起说,容易给人误解. 还是第2节中的例子,我们知道,<人员主集>.'国籍'和<代码项>.'代码项内码'的数据是有关联的,一般在我们的系统中,'国籍'中的数据

Access数据库多表连接查询

第一次在Access中写多表查询,就按照MS数据库中的写法,结果报语法错,原来Access的多表连接查询是不一样的 表A.B.C,A关联B,B关联C,均用ID键关联 一般写法:select * from A inner join B on A.ID=B.ID inner join C on B.ID=C.ID 此写法在Access中报错,Access对SQL语法理解方式不一样,它将两表连接后当作一个表然后再与第三个表连接,因此要改成 select * from (A inner join B o

实操-mysql表连接笛卡尔积(join、left join)

1.为什么两张表连接会出现重复数据 2.表的连接过程是怎样的? 举例: 表A: 1 0 表B: 1 0 0 2 执行语句:select * from A join B on A.id = B.id; 顺序如下: join形成的表: 1 1 1 0 1 0 1 2 0 1 0 0 0 0 0 2 on之后: 1 1 0 0 0 0 所以表连接后出现了重复数据 两张表的关系存在一对多的关系,所以就会出现重复情况 什么是笛卡尔积呢? 就是两张表连接的时候,是通过笛卡尔积的方式连接. 笛卡尔(Desca

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

A 一般情况下,Select Count (*)和Select Count(1)两着返回结果是一样的 假如表沒有主键(Primary key), 那么count(1)比count(*)快, 如果有主键的話,那主键作为count的条件时候count(主键)最快 如果你的表只有一个字段的话那count(*)就是最快的 count(*) 跟 count(1) 的结果一样,都包括对NULL的统计,而count(column) 是不包括NULL的统计 1.select 1 与 select *的区别 se

56 多表连接查询 索引

---恢复内容开始--- 主要内容 1 多表连接查询 语法: select 字段列表 from 表一 inner/left/right join 表二 on 表一.字段 = 表二.字段 内连接: 直连接匹配的行: select * from employee inner join department on employee.dep_id = department.id; select * from employee , department where  employee.dep_id = d

SQL优化之count,表的连接顺序、条件顺序,in和exist

一.关于count 看过一些关于count(*)和count(列)的文章,count(列)的效率一定比count(*)高吗? 其实个人觉得count(*)和count(列)根本就没有可比性,count(*)统计的是表里面的总条数,而count(列)统计的是当列的非空记录条数. 不过我们可以通过实验来比较一下: 首先创建测试表: drop table test purge; create table test as select * from dba_objects; update test  s

表连接查询与where后使用子查询的性能分析。

子查询就是在一条查询语句中还有其它的查询语句,主查询得到的结果依赖于子查询的结果. 子查询的子语句可以在一条sql语句的FROM,JOIN,和WHERE后面,本文主要针对在WHERE后面使用子查询与表连接查询的性能做出一点分析. 对于表连接查询和子查询性能的讨论众说纷纭,普遍认为的是表连接查询的性能要高于子查询.本文将从实验的角度,对这两种查询的性能做出验证,并就实验结果分析两种查询手段的执行流程对性能的影响. 首先准备两张表 1,访问日志表mm_log有150829条记录(相关sql文件已放在

表连接到底咋回事,就是产生中间结果啊!用于给select/insert等操作用

1.表连接到底咋回事,就是产生中间结果啊!用于给select/insert等操作用啊. 2.表连接产生的结果用于select/insert用 3.表连接产生的结果用于select/insert用 比如: sql = "select [个人信息$].*,[工作经历$].* from [个人信息$] inner Join [工作经历$] on [个人信息$].UID=[工作经历$].UID" 将表连接产生的中间结果用于select/insert操作等用 对比于传统的多表查询采用笛卡尔积,如

还在用SELECT COUNT统计数据库表的行数?Out了

在ABAP里我们如果想用代码获得一个数据库表里有多少条记录,常规做法是使用SELECT COUNT. 如果您使用的是HANA数据库,现在有一种新的办法可以达到同样的目的.HANA数据库里有一张名为m_tables的系统视图,里面存放了数据库表的元数据. 这个系统视图的详细说明参考SAP帮助文档. 我写了一个工具,可以通过查询m_tables来批量获得一系列数据库表的记录条数和占据的存储空间. 您可以通过这个链接获得我的工具的源代码.要获取更多Jerry的原创技术文章,请关注公众号"汪子熙&quo