首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

MySql左连接LEFT JOIN查询优化

用 MySql 查询多个表的数据时,我都会确定一张主表,然后用主表的主键去关联子表的外键进行左连接 left join,最后再把需要的字段一一查出来。

示例1:

SELECT m.id, L.some_column

FROM main_table m

LEFT JOIN left_table l ON m.id = l.main_id

在这个查询语句中,main_table 是主表,left_table 是子表。

这条语句首先将 main_table (m) 与 left_table (l) 进行左连接。左连接保证了 main_table 中的所有记录都会被显示出来,即便在 left_table 中找不到与之匹配的 main_id 记录。

这个左连接只适合主表和子表的数据一对一对应的情况。当主表对应子表的数据有多条时,这个sql语句就会查出来重复的主表数据,这条Sql语句就不适合了,我们需要改造一下。

示例2:

SELECT m.id, MAX(l.some_column) as some_column

FROM main_table m

LEFT JOIN left_table l ON m.id = l.main_id

GROUP BY m.id

在这个查询语句中,加了聚合函数 MAX 和分组的关键词 GROUP BY。

通过 GROUP BY m.id 来确保按照 main_table 的 id 对结果进行分组,对每个组使用 MAX 函数处理 some_column。

优点:

该查询确保 main_table 中的每一行都在结果中展示,无论是否在 left_table 中有匹配的记录。确保了主表数据的完整性。

该查询能够有效地聚合关联表中的数据,为每个主表记录提供一个最大值,这对于分析和报告可能非常有用。

缺点:

如果 left_table 很大,那么进行左连接和计算最大值可能会导致查询速度缓慢。此外,如果没有适当的索引(如在 left_table 的 main_id 上),性能可能会进一步下降。

这是我最常用的左连接写法。另外,天天用左连接,有点腻了,还有没有其他写法。

多种写法,多种选择。

示例3:

SELECT m.id,

(SELECT l.some_column

FROM left_table l

WHERE l.main_id = m.id

ORDER BY l.some_condition desc

LIMIT 1) as one_record

FROM main_table m;

这个查询语句采用了子查询,而且去掉了聚合函数,使用排序 order by 和 limit 限制。

子查询会在 left_table (l) 中查找与 m.id 对应的 main_id。然后,按照 l.some_condition 对结果进行降序排序。LIMIT 1 确保子查询只返回排序后的第一条记录的 some_column。

子查询返回的结果作为一个新列 one_record,与 main_table 的记录一起显示。

这种方法的核心在于子查询(SELECT ... FROM left_table ... LIMIT 1),它针对每一条主表的数据,仅返回左表中符合条件的一条记录。这个子查询可以根据需要进行排序,以便选择符合条件的第一条记录。

优点:

这个查询能够从 left_table 中为每一条 main_table 记录提取特定条件下的一个特定值,例如获取最新或最优或最大的记录。最终达到精准选择。

由于子查询可以包含 ORDER BY 和 LIMIT,因此可以根据需要灵活选择不同的记录,比如选择按时间最新的一条记录,或者按某个分数最高的一条记录。具有一定的灵活性。

缺点:

每条 main_table 记录都需要执行一次子查询,因此如果 main_table 非常大,或者子查询执行时间较长,整个查询的性能可能会受到严重影响。这会导致查询速度变慢,尤其是在 left_table 很大或没有适当的索引时。

复杂性:对于某些数据库系统,子查询可能会变得复杂且难以维护,尤其是在 left_table 的数据结构发生变化或需要进行复杂的排序时。

这个查询针对子表只查询一个字段时特别友好,如果要查询两个字段,就不适应了。

示例4:

SELECT m.id, l.max_column

FROM main_table m

LEFT JOIN (

SELECT main_id, MAX(column_to_maximize) as max_column

FROM left_table

GROUP BY main_id

) l ON m.id = l.main_id;

又回到左连接上,聚合函数也少不了。

左连接子查询从 left_table 中按 main_id 分组,并为每个组计算 column_to_maximize 的最大值,并将其命名为 max_column。生成一个由 main_id 和 max_column 组成的中间结果集。

主查询将 main_table 中的所有列与子查询结果进行左连接 (LEFT JOIN),连接条件是 m.id = l.main_id。

对于 main_table 中的每条记录,都会附加一个来自 left_table 中与之相关联的 max_column 值。如果 left_table 中没有匹配的记录,则 max_column 列为 NULL。

优点

清晰且结构化:通过使用子查询计算 MAX,查询语句变得更加清晰,将数据聚合逻辑与主查询分开处理,使得逻辑更易理解和维护。

性能较好:子查询只需计算一次 MAX(column_to_maximize) 并按 main_id 分组,这在一定程度上可以减少重复计算,提高性能,尤其是在 main_table 中记录较多的情况下。

扩展性:子查询方法允许在需要时很容易地扩展,以包括更多的聚合函数或不同的聚合条件。

缺点

可能的性能瓶颈:虽然性能相对不错,但如果 left_table 非常大且 main_id 没有适当的索引,子查询的聚合操作仍可能成为性能瓶颈。

复杂度增加:对于某些初学者或不熟悉 SQL 的开发人员,子查询结构可能显得复杂,特别是在维护和理解上。

最后总结

以上四种查询,第一种只有 left join ,sql 语句非常简单,但只适合于一对一的左连接。

第二种 max + left join + group by,也算简洁明了,直接在主查询中进行聚合操作,减少复杂度,适合需要获取简单聚合结果的场景。如果需要的不是聚合值而是其他条件下的单条记录,这种查询可能就无法满足需求。另外,在某些数据库系统中,使用 GROUP BY 可能会影响性能,尤其是在大数据集下。

第三种子查询,看起来非常灵活,允许根据任意条件(如时间、评分等)获取最相关的单条记录,可以按需排序并选择第一条记录。但是,性能可能较差,因为对于 main_table 中的每一条记录,子查询都会执行一次。另外,难以维护,尤其是在子查询逻辑复杂或表结构变动时。

第四种查询 left join + max + group by,子查询独立计算最大值,主查询相对简单,结构清晰。性能相对较好,子查询只执行一次聚合计算。但是,在 left_table 很大的情况下,子查询的性能可能受到影响。对于简单的需求,这种结构可能显得有些复杂。

这几种写法哪种好呢,抛开数据量谈性能都是耍流氓,数据量小的时候,怎么高兴怎么写,数据量大的时候再优化吧,没有一步到位的事情。就是不知道还有没有性能更好的写法。

  • 发表于:
  • 原文链接https://page.om.qq.com/page/OfwwATg3427XBx3tVheqEcuA0
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券