如何提高数据库 join 的效率 (数据库 join 效率)

数据库 join 是常用的查询操作之一,它是将两个或多个表中的数据进行关联的过程,可以通过这种方式获取到更加丰富的数据信息。不过,如果 join 的效率不高,会导致大量的时间和资源浪费,降低数据库的性能和应用的响应速度。因此,就变得非常重要了。

本文将从以下几个方面探讨:

1. 设计合理的表结构

2. 使用合适的 join 类型

3. 使用索引优化 join

4. 减少 join 表的大小

5. 避免在 join 条件中使用函数

6. 避免使用子查询

1. 设计合理的表结构

合理的表结构设计是数据库性能优化的关键之一,它可以直接影响到 join 的效率。在设计表结构时,需要根据实际业务需求,将数据尽可能地拆分到不同的表中,避免一个表中包含过多的字段和数据,从而减少 join 操作中的数据量,提高查询效率。

此外,在设计表结构时还需要注意表之间的关联,尽量使用外键来建立关联关系,这样可以更加方便地进行 join 操作,并且还能提高查询的准确性。

2. 使用合适的 join 类型

不同的 join 类型对查询效率影响很大,因此需要根据实际需求选择适合的 join 类型。下面简要介绍一下几种常见的 join 类型:

内连接(INNER JOIN):对两个表中的数据进行匹配,仅返回匹配成功的数据。INNER JOIN 的查询效率较高,但是无法查询到没有匹配的数据。

左连接(LEFT JOIN):返回左表中的所有数据,同时包含与右表匹配的数据,没有匹配成功的右表数据用 NULL 填充。LEFT JOIN 的查询效率较高,但是会增加查询的数据量。

右连接(RIGHT JOIN):返回右表中的所有数据,同时包含与左表匹配的数据,没有匹配成功的左表数据用 NULL 填充。RIGHT JOIN 的查询效率较低,而且并不是所有的数据库都支持 RIGHT JOIN。

全连接(FULL OUTER JOIN):返回两个表中所有的数据,并进行匹配。如果某一方没有匹配成功,则用 NULL 填充。FULL OUTER JOIN 的查询效率较低,而且并不是所有的数据库都支持 FULL OUTER JOIN。

3. 使用索引优化 join

索引是优化 join 查询效率的重要手段,可以大幅提高查询效率。在进行 join 操作前,需要为 join 的依据字段创建合适的索引,包括主键索引、唯一索引、普通索引等。不过,需要注意避免创建过多的索引,否则会降低数据库的性能。

4. 减少 join 表的大小

在进行 join 操作时,会将连接的表中的所有数据都加载到内存中,如果表的大小太大,那么 join 的效率就会非常低,甚至会导致内存不足的问题。因此,可以通过一些方式来减小 join 表的大小,例如分区或者分片、删除过期数据、归档历史数据等。

5. 避免在 join 条件中使用函数

在 join 的条件中使用函数会导致数据库无法使用索引,从而降低查询效率。因此,应该尽量避免在 join 条件中使用函数,可以将需要计算的值先计算出来,再将结果作为 join 条件。

6. 避免使用子查询

子查询是有些情况下必要的,但是过多使用会导致查询效率降低。在 join 中尽量避免使用子查询作为条件,可以通过改变查询的方式,将子查询的功能转换为 join 查询。

通过以上几个方面的优化,可以有效提高数据库 join 的效率,提升系统的性能和响应速度。在实际应用中,还可以根据具体情况进行优化,不断探索更加有效的优化方式。

相关问题拓展阅读:

使用MySQL的递延Join连接实现高效分页 – Aaron

在 Web 应用程序中跨大型数据集分页记录似乎是一个简单的问题,但实际上很难扩展。两种主要的分页策略是偏移/限制和游标。

我们将首先看一下这两种方法,然后稍作修改,可以使偏移/限制非常高效。

偏移/限制分页

偏移/限制方法是迄今为止最常见的方法,它通过跳过一定数量的记录(页)并将结果限制为一页来工作。

例如,假设您的应用程序配置为每页显示 15 条记录。您的 SQL 将如下所示:

这是最常见的,因为它非常简单,易于推理,并且几乎每个框架都支持它。

除了易于实现之外,它还具有页面可直接寻址的优点。例如,如果您想直接导航到第 20 页,您可以这样做,因为该偏移量很容易计算。

但是有一个主要的缺点,它潜伏在数据库处理偏移量尺雀的方式中。偏移量告诉数据库放弃从查询中返回的前N个结果。不过数据库仍然要从磁盘上获取这些行。

如果你丢弃的是100条记录,这并不重要,但如果你丢弃的是100,000条记录,数据库就会为了丢弃这些结果而做大量的工作。

在实践中,这意味着之一个页面会快速加载,之后的每一个页面都会变得越来越慢,直到你达到一个点,网络请求可能会直接超时。

基于游标的分页

基于游标的分页弥补了偏移/限制的一些不足,同时引入了一些自己的不足。

基于游标的分页是通过存储一些关于最后呈现给用户态滚的记录的状态,然后根据这个状态来进行下一次查询。

因此,它不是按顺序获取所有的记录并丢弃前N条,而是只获取最后一个位置N之后的记录。

如果按ID排序,SQL可能看起来像这样。

你可能已经看到了其中的好处。因为我们知道上次向用户展示的ID,我们知道下一个页面将以一个更高的ID开始。我们甚至不需要检查ID较低的行,因为我们百分之百肯定地知道那些行不需要被显示。

在上面的例子中,我特别说明了ID可能不帆困余是连续的,也就是说,可能有缺失的记录。这使得我们无法计算出哪些记录会出现在某一页面上,你必须跟踪之前那一页面上的最后一条记录是什么。

与偏移/限制分页不同,使用游标分页时,页面不能直接寻址,你只能导航到 “下一页 “或 “上一页”。

不过光标分页的好处是在任何数量的页面上都很迅速。它也很适合无限滚动,在这种情况下,页面首先不需要可以直接寻址。

Laravel文档中有一些关于偏移量和游标之间的权衡的好的背景。

cursor

-vs-offset-pagination

考虑到所有这些,让我们来看看一个偏移/限制优化,可以使它的性能足以在成千上万的页面上使用。

使用递延join的Offset/Limit

递延连接(deferred join )是一种技术,它将对要求的列的访问推迟到应用了偏移量和限制之后。

使用这种技术,我们创建一个内部查询,可以用特定的索引进行优化,以获得更大的速度,然后将结果连接到同一个表,以获取完整的行。

它看起来像这样:

这种方法的好处可以根据你的数据集有很大的不同,但是这种方法允许数据库尽可能少地检查数据,以满足用户的意图。

查询中 “昂贵的 “select *部分只在与内部查询相匹配的15条记录上运行。所有数据的Select都被推迟了,因此被称为推迟join。

这种方法不太可能比传统的偏移/限制性能差,尽管它是可能的,所以一定要在你的数据上进行测试!

Laravel实现

我们如何把这一点带到我们最喜欢的网络框架,如Laravel和Rails?

让我们具体看看Laravel,因为我不知道Rails。

感谢Laravel的macroable特性,我们可以扩展Eloquent Query Builder来添加一个新的方法,叫做deferredPaginate。为了保持一致性,我们将模仿常规分页的签名。

我们将尝试做尽可能少的自定义工作,并将大部分工作留给 Laravel。

这是我们要做的:

这应该为我们提供 LaravelLengthAwarePaginator 和延迟连接的所有好处!

一个Github仓库

递延Join和覆盖索引

还没有完成…

使用递延Join的主要好处是减少了数据库必须检索然后丢弃的数据量。我们可以通过帮助数据库获得它需要的数据而更进一步,而无需获取底层行。

这样做的方法称为“覆盖索引covering index”,它是确保快速偏移/限制分页的最终解决方案。

覆盖索引是一个索引,在这个索引中,查询的所有需要的字段都包含在索引本身中。当一个查询的所有部分都能被一个索引 “覆盖 “时,数据库根本不需要读取该行,它可以从索引中获得它需要的一切。

请注意,覆盖索引并不是以任何特殊方式创建的。它只是指一个索引满足了一个查询所需要的一切的情况。一个查询上的覆盖索引很可能不是另一个查询上的覆盖索引。

在接下来的几个例子中,我们将使用这个基本的表,我把它填满了~1000万条记录。

让我们看一个仅select索引列的简单查询。在这种情况下,我们将从email表中进行select contacts。

在这种情况下,数据库根本不需要读取基础行。在MySQL中,我们可以通过运行一个解释并查看额外的列来验证这一点:

extra: using index告诉我们,MySQL能够只使用索引来满足整个查询,而不看基础行。

如果尝试select name from contacts limit 10, 我们将期望MySQL必须到该行去获取数据,因为名字name没有被索引。这正是发生的情况,由下面的解释显示。

extra不再显示 using index,所以我们没有使用覆盖索引。

假设你每页有15条记录,你的用户想查看第1001页,你的内部查询最终会是这样的。

select id from contacts order by id limit 15 OFFSET

explain结果显示:

MySQL能够单看索引来执行这个查询。它不会简单地跳过前15万行,在使用offset是没有办法的,但它不需要读取15万行。(只有游标分页可以让你跳过所有的行)。

即使使用覆盖索引和延迟连接,当你到达后面的页面时,结果也会变慢,尽管与传统的偏移/限制相比,它应该是最小的。使用这些方法,你可以轻易地深入到数千页。

更好的覆盖索引

这里的很多好处取决于拥有良好的覆盖索引,所以让我们稍微讨论一下。一切都取决于您的数据和用户的使用模式,但是您可以采取一些措施来确保查询的更高命中率。

这将主要与 MySQL 对话,因为那是我有经验的地方。其他数据库中的情况可能会有所不同。

大多数开发人员习惯于为单列添加索引,但没有什么能阻止您向多列添加索引。事实上,如果您的目标是为昂贵的分页查询创建覆盖索引,您几乎肯定需要一个多列索引。

当你试图为分页优化一个索引时,一定要把按列排序放在最后。如果你的用户要按update_at排序,这应该是你复合索引中的最后一列。

看看下面这个包括三列的索引。

在MySQL中,复合索引是从左到右访问的,如果一个列缺失,或者在之一个范围条件之后,MySQL会停止使用一个索引。

MySQL 将能够在以下场景中使用该索引:

如果你跳过is_archived,MySQL将无法访问update_at,将不得不诉诸于没有该索引的排序,或者根本不使用该索引,所以要确保你有相应的计划。

主键始终存在

在MySQL的InnoDB中,所有的索引都附加了主键。这意味着(email)的索引实际上是(email,id)的索引,当涉及到覆盖索引和延迟连接时,这是相当重要的。

查询select email from contacts order by id完全被email上的一个索引所覆盖,因为InnoDB将id附加到了该索引上。

使用我们上面的综合例子,你可以看到这有什么好处。

因为复合索引涵盖了is_deleted, is_archived, updated_at, 和(通过InnoDB的功能)id,整个查询可以仅由索引来满足。

降序索引

大多数时候,用户都在寻找 “最新的 “项目,即最近更新或创建的项目,这可以通过按update_at DESC排序来满足。

如果你知道你的用户主要是以降序的方式对他们的结果进行排序,那么特别将你的索引设为降序索引可能是有意义的。

MySQL 8是之一个支持降序索引的MySQL版本。

如果你在explain的Extra部分看到向后索引扫描,你也许可以配置一个更好的索引。

前向索引扫描比后向扫描快~15%,所以你要按照你认为你的用户最常使用的顺序添加索引,并为少数使用情况承担惩罚。

太阳底下无新事

这种使用偏移/限制分页与延迟连接和覆盖索引的方法并不是银弹。

仅仅是递迟连接就可以让你的速度得到很好的提升,但是需要花一些额外的心思来设计正确的索引以获得更大的好处。

有一种观点认为,递延连接应该是框架中默认的偏移offset/限制limit方法,而任何时候覆盖索引的出现都只是一种奖励。我还没有在足够多的生产环境中测试过,所以还没有强烈主张这样做。

使用MySQL的递延Join连接实现高效分页 – Aaron

sql语句中 用 inner join 连接两张表,大表放在前面比较快还是小表放在前面比较快。

晕,你就连接两张表,要什么速度快啊,一般把大表放在前面!

小表在前可以提高sql执行效率。

首先将大表放在前面,即如图(tmp2表数据量为40亿,tmp1数据量只有81条),这样执行时间为3小时21分钟,然后再将小表放在前面,执行速度为10分钟。

扩展资料:

结构化查询语言

包含6个部分:

1、数据查询语言(DQL:Data Query Language):其语句,也称为“数据检索语句”,用以从表中获得数据,确定数据怎样在

应用程序

给出。

保留字SELECT是乎铅DQL(也是所有SQL)用得最多的动词,其他DQL常用的保留字有WHERE,ORDER BY,

GROUP BY

和HAVING。这些DQL保留字常与其它类型的SQL语句一起使用。 

2、数据操作岁岁好语言(DML:Data Manipulation Language):其语句包括动词INSERT、UPDATE和DELETE。它们分别用于添加、修改和删除。

3、事务控制语言(TCL):它的语句能确保被DML语句影响的表的所有行及时得以更新。包括COMMIT(提交)命令、SAVEPOINT(保存雀宽点)命令、ROLLBACK(回滚)命令。

4、数据控制语言(DCL):它的语句通过GRANT或REVOKE实现权限控制,确定单个用户和用户组对数据库对象的访问。某些RDBMS可用GRANT或REVOKE控制对表单个列的访问。

5、数据定义语言(DDL):其语句包括动词CREATE,ALTER和DROP。在数据库中创建新表或修改、删除表(CREAT TABLE 或 DROP TABLE);为表加入索引等。

6、指针控制语言(CCL):它的语句,像DECLARE CURSOR,FETCH INTO和UPDATE WHERE CURRENT用于对一个或多个表单独行的操作。

参考资料:

百度百科——sql语句

一样快。因为Inner join是不分主从表的,结果是取两个表针对On条扒数件相匹配的最小集。

5G的表,得需要多大的服毁腔务器资源来处理?

建议春余首你首先针对两张表做Where条件筛选,然后再做Join。

一样的。应该是同时检索,做好用存储过程会快点。

关于数据库 join 效率的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。


数据运维技术 » 如何提高数据库 join 的效率 (数据库 join 效率)