数据库级联操作的深度分析对比

2025-03-27 12:58
455
0

下文都通过如下示例表进行查询示例

-- 创建表A
CREATE TABLE A (
    id INT PRIMARY KEY,
    name VARCHAR(50)
);

-- 插入数据到表A
INSERT INTO A (id, name) VALUES
(1, 'Alice'),
(2, 'Bob'),
(3, 'Charlie');

-- 创建表B
CREATE TABLE B (
    id INT,
    count INT
);

-- 插入数据到表B
INSERT INTO B (id, count) VALUES
(1, 5),
(1, 15),
(2, 20);

一、级联操作介绍

1.1、内连接(INNER JOIN)

内连接其作用是返回两个表中满足连接条件的交集部分。即两个表的数据要同时满足连接条件,才会用于进行连接。

SQL示例:

SELECT A.id, A.name, B.count FROM A INNER JOIN B ON A.id = B.id;

应用场景:当需要精确匹配两个表的数据,过滤掉无关记录时使用,例如在订单系统中查询订单和商品信息,只显示有对应商品的订单

1.2、外连接

外连接它不仅会返回满足连接条件的行,还会保留某一侧表中不满足条件的行。常见的外连接类型有左外连接(LEFT JOIN)和右外连接(RIGHT JOIN)。这里以左外连接为例进行说明,左外连接会保留左表的所有行,右表中匹配的行正常显示数据,若右表中无匹配行,则相应列显示为 NULL。

左外连接示例:

SELECT A.id, A.name, B.count FROM A LEFT JOIN B ON A.id = B.id;

应用场景:当需要保留主表的所有数据,同时关联从表的可选数据时使用,如在员工信息系统中,查询所有员工信息并关联其部门信息,即使部分员工没有分配部门

1.3、隐式连接

隐式连接是一种通过逗号分隔表名,并在 WHERE 子句中指定连接条件的连接方式。其本质是先对参与连接的表进行笛卡尔积操作,然后再根据 WHERE 子句的条件进行过滤。

示例:

SELECT A.id, A.name, B.count FROM A, B WHERE A.id = B.id;

应用场景:主要用于兼容旧代码或者进行简单查询,但由于其性能和可读性的问题,在SQL 开发中不建议频繁使用

二、三种SQL写法的对比分析

如下先给出三个SQL查询语句,然后我们一起来分析下它们的执行情况,进行对比分析。

-- SQL1
SELECT A.id, A.name, B.count FROM A LEFT JOIN B ON A.id = B.id AND B.count > 10;
-- SQL2
SELECT A.id, A.name, B.count FROM A LEFT JOIN B ON A.id = B.id WHERE B.count > 10;
-- SQL3
SELECT A.id, A.name, B.count FROM A, B WHERE A.id = B.id AND B.count > 10;

第一种写法:

  • on 子句用来确定表 A 和表 B 的连接条件,同时添加了筛选条件 B.count > 10。
  • 在进行左连接时,会保留左表 A 的所有行。对于右表 B,只有满足 A.id = B.id 且 B.count > 10 的行才会参与连接,若右表中无满足条件的行,则对应列显示为 NULL。
  • 特点:可以确保左表的所有数据都被保留,同时对右表的数据进行筛选。

第二种写法:

  • on 子句用来确定表 A 和表 B 的连接条件,筛选条件 B.count > 10放到where中。
  • 先进行左连接操作,将左表 A 的所有行与右表 B 中满足 A.id = B.id 的行进行连接,生成一个中间结果集。
  • 然后,通过 WHERE 子句对这个中间结果集进行筛选,只保留 B.count > 10 的行。
  • 特点:左表的数据也会根据筛选条件 B.count > 10进行筛选。

第三种写法:

  • 这种写法使用了传统的隐式连接语法。
  • 数据库首先会对表 A 和表 B 进行笛卡尔积操作,生成一个包含所有可能的行组合的结果集。
  • 然后,WHERE 子句会对这个笛卡尔积结果集进行筛选,只保留满足 A.id = B.id 并且 B.count > 10 的行。
  • 特点:最终的结果同样是同时满足这两个条件的行的集合,和第二种写法一致。但因为用的是笛卡尔积生成的关联数据,会产生大量的中间结果,可能导致性能显著下降。

扩展,用如下SQL可以查询出A表和B表的笛卡尔积数据示例:

-- 笛卡尔积
SELECT A.id, A.name, B.count FROM A, B;

在大多数数据库中,第一种写法和第二种写法的性能差异不大,数据库优化器通常会对它们进行类似的处理。

内连接的这3种写法类似,只是内连接取的是交集,三种写法显示的结果会一样,但不同写法性能上会有区别。

三、总结

  • 优先使用显式连接:如INNER JOIN、LEFT JOIN等,提高查询的可读性和可维护性。
  • 合理放置条件:在外连接中,要保留主表数据,就把筛选条件应放在ON子句中,避免因WHERE子句导致数据丢失。
  • 避免隐式连接:除非必要,否则不使用逗号分隔表名的方式,以减少性能开销和逻辑错误。

全部评论