优化专利链接体系(优化转段)

lxf2023-05-10 09:50:01

前言

有人反馈,之前的文章理论性太强,缺乏实践细节,所以这篇文章应该更有操作性的内容。

注意:本文基于MySQL,很多内容也适用于其他关系数据库,需要一定的索引知识。

优化目标

1.减少IO次数

IO永远是数据库最瓶颈的地方,这是数据库的职责决定的。大多数数据库操作90%以上的时间都被IO操作占用。减少IO次数是SQL优化的第一要务,当然也是最有效的优化方法

2.减少CPU计算

除了IO瓶颈,SQL优化还要考虑CPU计算的优化。Order by、group by、distinct……都是CPU的消耗大户(这些操作基本都是CPU在内存中处理数据比较操作)。当我们的IO优化到了一定阶段,减少CPU计算就成了我们SQL优化的重要目标。

优化方法

更改SQL执行计划

在明确优化目标后,我们需要确定实现目标的方法。对于SQL语句来说,要达到上述两个目的,其实只有一个办法,那就是改变SQL的执行计划,让他“少走弯路”,通过各种“捷径”尽量找到我们需要的数据,达到“减少IO次数”和“减少CPU计算”的目的

常见误解

1.count(1)和count(primary_key)比count(*)好。

许多人使用count(1)和count(primary_key)而不是count(*)来计算记录的数量。他们认为这样性能更好,但这其实是一种误解。对于某些场景,性能可能会更差,应该对数据库的count(*)操作进行一些特殊的优化。

2.count(列)和count(*)是相同的。

这种误解甚至存在于很多高级工程师或者DBA身上,很多人会觉得理所当然。其实count(column)和count(*)是完全不同的操作,意义完全不同。

Count(column)指示结果集中列字段不是空的记录的数量。

Count(*)表示整个结果集中有多少条记录。

3.select a,b from …可以使数据库访问的数据比select a,b,c from …少。

这种误解主要存在于大量的开发人员中,主要是因为他们对数据库的存储原理了解不多。

事实上,大多数关系数据库都是以行的形式存储的,数据访问操作是基于一个固定大小的IO单元(称为块或页),一般为4KB、8 KB...大多数时候,每个IO单元存储多行,每行存储该行的所有字段(lob等特殊类型的字段除外)。

所以,不管我们取一个字段还是多个字段,其实数据库在表中需要访问的数据量其实是一样的。

当然也有例外,就是我们的查询可以在索引中完成,也就是只取A和B两个字段时,不需要返回表,而C字段不在使用的索引中,需要返回表来获取它的数据。在这种情况下,两个IO量会有很大的差异。

4.order by必须需要排序操作。

我们知道索引数据实际上是有序的。如果我们需要的数据的顺序与一个索引的顺序一致,并且我们的查询是通过这个索引执行的,那么数据库一般会省略排序操作,直接返回数据,因为数据库知道数据已经满足了我们的排序要求。

实际上,利用索引对有排序需求的SQL进行优化是一种非常重要的优化方法。

延伸阅读:MySQL ORDER BY的实现分析,MySQL中GROUP BY的基本实现原理,MySQL DISTINCT的基本实现原理都有比较深入的分析,尤其是第一条。

5.如果执行计划中有文件排序,磁盘文件将被排序。

其实不能怪这种误解,而是因为MySQL开发者在用词上的问题。当我们使用explain命令查看SQL的执行计划时,文件排序是我们可能会在“Extra”列中看到的信息。

其实只要一条SQL语句需要排序,就会显示“使用文件排序”,并不代表会有文件排序操作。

基本原则

1.尽量少加入

MySQL的优势在于简单,但这其实是它在某些方面的劣势。MySQL优化器效率高,但由于统计信息量有限,优化器工作过程中出现偏差的可能性更大。对于复杂的多表连接,一方面是其优化器有限,另一方面是在连接这方面做的努力不够,所以性能与Oracle等关系数据库前辈还有很大差距。但如果是简单的单表查询,差距会很小,甚至在某些场景下比这些数据库前辈还要好。

2.尽可能少排序

排序操作会消耗更多的CPU资源,所以在缓存命中率高、IO能力充足的场景下,减少排序会极大地影响SQL的响应时间。

对于MySQL,有许多方法可以减少排序,例如:

上面误解中提到的优化,就是用索引来排序的。

减少参与排序的记录数量。

没有必要对数据进行排序。

3.尽量避免选择*

很多人看到这里后很难理解。你刚才不是在误区里说select子句中的字段个数不会影响读取的数据吗?

是的,大部分时候不会影响IO数量,但是当我们还有order by操作的时候,select子句中的字段会在很大程度上影响我们的排序效率,这一点可以在我之前介绍MySQL ORDER BY的实现分析的文章中详细介绍。

另外,上面的误区里没有说,但是大部分时候不会影响IO量。当我们的查询结果只能在索引中找到时,还是会大大降低IO量。

4.尝试使用联接而不是子查询。

Join虽然性能不好,但相比MySQL子查询还是有很大的性能优势。MySQL的子查询执行计划一直存在很大的问题。虽然这个问题已经存在很多年了,但是在目前已经发布的所有稳定版本中都很常见,并没有得到很大的改善。虽然官方早就承认了这个问题,并承诺会尽快解决,但至少到目前为止我们还没有看到哪个版本解决这个问题更好。

5.尝试最小化或

当where子句中有多个条件与“or”共存时,MySQL的优化器并没有很好地解决其执行计划的优化问题。此外,MySQL独特的SQL和存储分层架构导致其性能低下。在很多情况下,使用union all或union(必要时)代替“or”会得到更好的结果。

6.尝试用union all替换union。

union和union all的主要区别在于,前者需要将两个(或多个)结果合并后再进行唯一的过滤操作,这会涉及到排序,增加大量的CPU操作,增加资源消耗和延迟。所以当我们可以确认重复结果集是不可能的或者不在乎重复结果集的时候,尽量使用union all而不是union。

7.尽早过滤

事实上,这种优化策略最常用于索引的优化设计(将过滤效果较好的字段放在前面)。

这个原理也可以用来优化SQL编写中的一些Join SQL。比如我们在查询多个表中分页的数据时,最好能够将一个表中的数据筛选出来并分页,然后用分页的结果集与另一个表连接,这样可以尽可能减少不必要的IO操作,大大节省IO操作所消耗的时间。

8.避免类型转换

这里所说的“类型转换”是指当where子句中列字段的类型与传入参数的类型不一致时发生的类型转换:

通过转换函数对column_name进行人工转换。

直接导致MySQL(其实其他数据库也会有同样的问题)无法使用索引,如果必须转换,就要在传递的参数上进行转换。

由数据库本身转换。

如果我们传入的数据类型和字段类型不一致,并且我们没有做任何类型转换,MySQL可能会自己转换我们的数据,或者不做处理就留给存储引擎处理。这样,索引将不会被使用,从而导致执行计划问题。

9.优先优化高并发的SQL,而不是一些执行频率低的“大”SQL。

对于破坏性来说,高并发SQL永远比低频SQL大,因为一旦高并发SQL出现问题,它会把系统压垮,甚至不给我们任何喘息的机会。对于一些IO消耗较大,响应较慢的SQL,由于频率较低,即使遇到,最多也会让整个系统响应较慢,但至少可能会持续一段时间,给我们一个缓冲的机会。

10.从全局优化,而不是片面调整

SQL优化不能针对一个,要充分考虑系统中的所有SQL,尤其是通过调整索引来优化SQL的执行计划时,千万不能顾此失彼。

11.尽可能多地解释数据库中运行的每一条SQL。

要优化SQL,我们需要心中有数。只有了解SQL的执行计划,才能判断是否有优化的空间,是否存在执行计划问题。对数据库中运行一段时间的SQL进行优化后,很明显SQL问题可能很少,大部分都是需要发现的。这时候就需要大量的解释操作来收集执行计划,判断是否需要优化。

原地址:/d/file/04/j4yjre4qqh08634.html;jsessionid=A00BB6D36CADD471BEEDF08516F27EC4 adminjs.cn是一个以CSS、JavaScript、Vue、HTML为核心的前端开发技术网站。我们致力于为广大前端开发者提供专业、全面、实用的前端开发知识和技术支持。 在本网站中,您可以学习到最新的前端开发技术,了解前端开发的最新趋势和最佳实践。我们提供丰富的教程和案例,让您可以快速掌握前端开发的核心技术和流程。 Adminjs.cn还提供一系列实用的工具和插件,帮助您更加高效地进行前端开发工作。我们提供的工具和插件都经过精心设计和优化,可以帮助您节省时间和精力,提升开发效率。 在Adminjs.cn中,您可以找到您需要的一切前端开发资源,让您成为一名更加优秀的前端开发者。欢迎您加入我们的大家庭,一起探索前端开发的无限可能!