优化联合 sql 查询

Posted

技术标签:

【中文标题】优化联合 sql 查询【英文标题】:Optimizing a union sql query 【发布时间】:2013-05-23 00:22:32 【问题描述】:

我在 3 个表之间做一个 UNION。为了让您了解情况,一张表被视为主表,另外两张表被视为子表。 2 个子表对于每种情况始终具有相同数量的记录。所以我想在这3个表之间建立一个联合,在这个联合中我想重复在主表中获取的列中的信息,并列出2个子表的信息,其中子表1中的每一行都对应于该行在子表2中。由于专业原因,我无法放置真实的代码,所以这里是一个与我的真实案例相对应的简单示例。 考虑一个名为 Author (Author_ID, Author_FirstName, Author_LastName) 的表。该表将是我们的主表。然后考虑我们有一个名为 Adresses (Adress_ID, Street_Coord, Author_ID) 的表,这将是我们的子表 1。然后考虑名为 Cities 的表 (City_ID, City_Name, Author_ID)。我们的作者 X 在 2 个城市有 2 个地址。当我执行我的查询时,我得到了完全合乎逻辑的结果 R1,但我想修改我的查询以获得结果 R2。您能帮我更改查询以获得结果 R2 吗?

SQL 查询:

SELECT "Author"."Author_ID", "Author"."Author_FirstName", "Author.Author_LastName",
       TO_CHAR(NULL) AS "Street_Coord", TO_CHAR(NULL) AS "City_Name"
FROM "Author"
WHERE "Author"."Author_ID"='X'

UNION

SELECT TO_NUMBER(NULL) AS "Author_ID", TO_CHAR(NULL) AS "Author_FirstName", TO_CHAR(NULL) AS "Author_LastName", 
       "Adresses"."Street_Coord", TO_CHAR(NULL) AS "City_Name" 
FROM "Adresses"
WHERE "Adresses"."Author_ID"='X'

UNION

SELECT TO_NUMBER(NULL) AS "Author_ID", TO_CHAR(NULL) AS "Author_FirstName", TO_CHAR(NULL) AS "Author_LastName", 
       TO_CHAR(NULL) AS "Street_Coord", "Cities"."City_Name"
FROM "Cities"
WHERE "Cities"."Author_ID"='X'

结果 R1:

ID_AUTHOR | AUTHOR_FirstName | AUTHOR_LastName | Street_Coord   | City_Name       |
----------------------------------------------------------------------------------
X         |James             | Conor           | NULL           | NULL            |
----------------------------------------------------------------------------------
X         |NULL              | NULL            | 1245 rich st   | NULL            |
----------------------------------------------------------------------------------
X         |NULL              | NULL            | 154 music st   | NULL            |
----------------------------------------------------------------------------------
X         |NULL              | NULL            | NULL           | Madrid          |
----------------------------------------------------------------------------------
X         |NULL              | NULL            | NULL           | Barcelona       |
----------------------------------------------------------------------------------

结果 R2:我希望你帮助得到这个结果:

ID_AUTHOR | AUTHOR_FirstName | AUTHOR_LastName | Street_Coord   | City_Name       |
----------------------------------------------------------------------------------
X         |James             | Conor           | 1245 rich st   | Madrid          |
----------------------------------------------------------------------------------
X         |James             | Conor           | 154 music st   | Barcelona       |
----------------------------------------------------------------------------------

非常感谢, 瓦卢德

【问题讨论】:

您确定不想要 JOIN 而不是 UNION? 嘿 eaolson,11 个表的连接崩溃了! ORA-01652:无法在表空间 TEMP 01652 中将临时段扩展 128。00000 -“无法在表空间 %s 中将临时段扩展 %s” *原因:无法为临时段分配所需块数的范围在指示的表空间中。 *操作:使用 ALTER TABLESPACE ADD DATAFILE 语句将一个或多个文件添加到指定的表空间。 该错误听起来像是您需要扩展 TEMP 表空间的大小。 ***.com/questions/11839576/… 【参考方案1】:

首先想到的是您真的想将这些表连接在一起。比如:

SELECT "Author"."Author_ID", "Author"."Author_FirstName", "Author.Author_LastName",
       "Adresses"."Street_Coord", "Cities"."City_Name"
FROM "Author" join
     "Adresses"
     on Author.Author_id = Adresses.Author_id join
     Cities
     on Author.Author_id = Cities.Author_id 
WHERE "Author"."Author_ID"='X';

但是,这将返回值的笛卡尔积,即 4 行而不是 2 行。似乎目的是“对齐”不同的表格。在这种情况下,这个查询接近你想要的:

SELECT "Author"."Author_ID", "Author"."Author_FirstName", "Author.Author_LastName",
       "Adresses"."Street_Coord", "Cities"."City_Name"
FROM "Author" join
     (select a.*, rownum as seqnum from "Adresses" a
     ) Adresses
     on Author.Author_id = Adresses.Author_id join
     (select c.*, rownum as seqnum from Cities c
     ) Cities
     on Author.Author_id = Cities.Author_id and addresses.seqnum = cities.seqnum
WHERE "Author"."Author_ID"='X';

这种方法的主要问题是 SQL 表本质上是无序的。您需要一些列来对这些进行排序,以保证查询正常工作。例如,如果您在表中有一个自动递增的 id,那么每个子查询可以是 order by id

【讨论】:

我怀疑你的第一个答案是 Walloud 打算,但是 Cities 需要一个 address_id 而不是 author_id。 @eaolson 。 . . OP 非常清楚表格包含的内容。结构绝对不寻常。我猜它类似于具有不同列的表单上的线条。 大家好,在现实世界中我有 11 张桌子!当我在 11 个表上使用 JOIN 时,由于返回的记录数量很大,Oracle 崩溃了,这就是我使用 UNION 的原因。我只能用 UNION 找到解决方案。再次感谢! 这没有意义。这是两种不同的操作。一个 JOIN 基本上会给你额外的列,一个 UNION 会给你更多的行。这就好像你在问如何转动汽车,但你不会使用方向盘,所以你想知道如何只用油门踏板。 @Walloud。 . .我的猜测是 Oracle 崩溃是因为连接设置不正确。处理 11 个表对 Oracle 来说应该没有问题。【参考方案2】:

你不想做一个 UNION,你想做一个 JOIN :

SELECT "Author"."Author_ID", "Author"."Author_FirstName", "Author.Author_LastName", "Adresses"."Street_Coord", "Cities"."City_Name"
 FROM "Author"
 INNER JOIN "Adresses" ON "Author"."Author_ID"="Adresses"."Author_ID"
 INNER JOIN "Cities" ON "Author"."Author_ID"="Cities"."Author_ID"
 WHERE "Author"."Author_ID"='X'

没有测试,可能有错别字...

此外,您需要在“地址”和“城市”之间添加一个额外的连接列,以将“1245 Rich st”与“Madrid”、“154 music st”和“Barcelona”相匹配。类似“City_ID”的东西。然后将其添加到 INNER JOIN ... ON 子句中:

INNER JOIN "Cities" ON "Adresses"."City_ID"="Cities"."City_ID" AND "Author"."Author_ID"="Cities"."Author_ID"

【讨论】:

大家好,在现实世界中我有 11 张桌子!当我在 11 个表上使用 JOIN 时,由于返回的记录数量很大,Oracle 崩溃了,这就是我使用 UNION 的原因。我只能用 UNION 找到解决方案。再次感谢! 那么,您可能应该执行多个查询。在您的示例中,您可以执行对作者信息(例如名字和姓氏)的查询,以及对地址和城市的单独查询。这更有意义,并且您将获取比单个大胖查询更少的数据。 嘿 Walloud,这里的人是对的,你应该使用 JOIN 语句而不是 UNION 语句。如果您遇到 ORA-01652 问题,请尝试“调试”它,首先尝试连接 2 个表,然后每次尝试将另一个表添加到您的查询中,并尝试了解哪些表导致查询抛出异常( ORA-01652) , 理解后, 尝试通过添加索引来优化它(例如在目标表中的author_id上)

以上是关于优化联合 sql 查询的主要内容,如果未能解决你的问题,请参考以下文章

SQL联合子句优化

MySql知识体系总结(SQL优化篇)

mysql 多表联合查询啥用

SQL Server调优系列基础篇(联合运算符总结)

ASP ACCESS 多表联合查询问题

SQL两张表联合查询