一、性能优化简介

什么是性能:

  • 我们将性能定义为完成某件任务所需要的时间度量,换句话说,性能即响应时间,这是一个非常重要的原则
  • 我们通过任务和时间而不是资源来测量性能。数据库服务器的目的是执行SQL语句,所以它关注的任务是查询或者语句,如SELECT、UPDATE、DELETE等。数据库服务器 的性能用查询的响应时间来度量,单位是每个查询花费的时间

什么是优化

  • 很多人对此很迷茫。假如你认为性能优化是降低CPU利用率,那么 可以减少对资源的使用。但这是一个陷阱,资源是用来消耗并用来工作 的,所以有时候消耗更多的资源能够加快查询速度。很多时候将使用老 版本InnoDB引擎的MySQL升级到新版本后,CPU利用率会上升得很厉 害,这并不代表性能出现了问题,反而说明新版本的InnoDB对资源的 利用率上升了。查询的响应时间则更能体现升级后的性能是不是变得更 好。版本升级有时候会带来一些bug,比如不能利用某些索引从而导致 CPU利用率上升。CPU利用率只是一种现象,而不是很好的可度量的目 标
  • 同样,如果把性能优化仅仅看成是提升每秒查询量,这其实只是吞吐量优化。吞吐量的提升可以看作性能优化的副产品。对查询的优化 可以让服务器每秒执行更多的查询,因为每条查询执行的时间更短了 (吞吐量的定义是单位时间内的查询数量,这正好是我们对性能的定义 的倒数)
  • 所以如果目标是降低响应时间,那么就需要理解为什么服务器执行 查询需要这么多时间,然后去减少或者消除那些对获得查询结果来说不 必要的工作。也就是说,先要搞清楚时间花在哪里。这就引申出优化的 第二个原则:无法测量就无法有效地优化。所以第一步应该测量时间花 在什么地方
  • 我们观察到,很多人在优化时,都将精力放在修改一些东西上,却 很少去进行精确的测量。我们的做法完全相反,将花费非常多,甚至 90%的时间来测量响应时间花在哪里。如果通过测量没有找到答案,那 要么是测量的方式错了,要么是测量得不够完整。如果测量了系统中完 整而且正确的数据,性能问题一般都能暴露出来,对症下药的解决方案 也就比较明了。测量是一项很有挑战性的工作,并且分析结果也同样有 挑战性,测出时间花在哪里,和知道为什么花在那里,是两码事
  • 前面提到需要合适的测量范围,这是什么意思呢?合适的测量范围 是说只测量需要优化的活动。有两种比较常见的情况会导致不合适的测 量:
    • 在错误的时间启动和停止测量
    • 测量的是聚合后的信息,而不是目标活动本身
  • 完成一项任务所需要的时间可以分成两部分:执行时间和等待时 间。如果要优化任务的执行时间,最好的办法是通过测量定位不同的子 任务花费的时间,然后优化去掉一些子任务、降低子任务的执行频率或 者提升子任务的效率。而优化任务的等待时间则相对要复杂一些,因为 等待有可能是由其他系统间接影响导致,任务之间也可能由于争用磁盘 或者CPU资源而相互影响。根据时间是花在执行还是等待上的不同,诊 断也需要不同的工具和技术
  • 刚才说到需要定位和优化子任务,但只是一笔带过。一些运行不频 繁或者很短的子任务对整体响应时间的影响很小,通常可以忽略不计。 那么如何确认哪些子任务是优化的目标呢?这个时候性能剖析就可以派 上用场了

高性能MySQL:15---服务器性能剖析之性能优化、通过性能剖析进行优化、理解性能剖析

二、通过性能剖析进行优化

  • 一旦掌握并实践面向响应时间的优化方法,就会发现需要不断地对系统进行性能剖析(profiling)
  • 性能剖析是测量和分析时间花费在哪里的主要方法。性能剖析一般 有两个步骤:测量任务所花费的时间;然后对结果进行统计和排序,将 重要的任务排到前面
  • 性能剖析工具的工作方式基本相同。在任务开始时启动计时器,在 任务结束时停止计时器,然后用结束时间减去启动时间得到响应时间。 也有些工具会记录任务的父任务。这些结果数据可以用来绘制调用关系 图,但对于我们的目标来说更重要的是,可以将相似的任务分组并进行 汇总。对相似的任务分组并进行汇总可以帮助对那些分到一组的任务做 更复杂的统计分析,但至少需要知道每一组有多少任务,并计算出总的 响应时间。通过性能剖析报告(profile report)可以获得需要的结果。 性能剖析报告会列出所有任务列表。每行记录一个任务,包括任务名、 任务的执行时间、任务的消耗时间、任务的平均执行时间,以及该任务 执行时间占全部时间的百分比。性能剖析报告会按照任务的消耗时间进 行降序排序
  • 为了更好地说明,这里举一个对整个数据库服务器工作负载的性能 剖析的例子,主要输出的是各种类型的查询和执行查询的时间。这是从 整体的角度来分析响应时间,后面会演示其他角度的分析结果。下面的 输出是用Percona Toolkit中的pt-query-digest(实际上就是著名的Maatkit 工具中的mk-query-digest)分析得到的结果。为了显示方便,对结果做 了一些微调,并且只截取了前面几行结果:

高性能MySQL:15---服务器性能剖析之性能优化、通过性能剖析进行优化、理解性能剖析

  • 上面只是性能剖析结果的前几行,根据总响应时间进行排名,只包 括剖析所需要的最小列组合。每一行都包括了查询的响应时间和占总时 间的百分比、查询的执行次数、单次执行的平均响应时间,以及该查询 的摘要。通过这个性能剖析可以很清楚地看到每个查询相互之间的成本 比较,以及每个查询占总成本的比较。在这个例子中,任务指的就是查 询,实际上在分析MySQL的时候经常都指的是查询
  • 我们将实际地讨论两种类型的性能剖析:基于执行时间的分析和基 于等待的分析。基于执行时间的分析研究的是什么任务的执行时间最 长,而基于等待的分析则是判断任务在什么地方被阻塞的时间最长
  • 如果任务执行时间长是因为消耗了太多的资源且大部分时间花费在 执行上,等待的时间不多,这种情况下基于等待的分析作用就不大。反 之亦然,如果任务一直在等待,没有消耗什么资源,去分析执行时间就 不会有什么结果。如果不能确认问题是出在执行还是等待上,那么两种 方式都需要试试。后面会给出详细的例子
  • 事实上,当基于执行时间的分析发现一个任务需要花费太多时间的 时候,应该深入去分析一下,可能会发现某些“执行时间”实际上是在等 待。例如,上面简单的性能剖析的输出显示表InvitesNew上的SELECT查 询花费了大量时间,如果深入研究,则可能发现时间都花费在等待I/O 完成上
  • 在对系统进行性能剖析前,必须先要能够进行测量,这需要系统可 测量化的支持。可测量的系统一般会有多个测量点可以捕获并收集数 据,但实际系统很少可以做到可测量化。大部分系统都没有多少可测量 点,即使有也只提供一些活动的计数,而没有活动花费的时间统计。 MySQL就是一个典型的例子,直到版本5.5才第一次提供了Performance Schema,其中有一些基于时间的测量点(4),而版本5.1及之前的版本没 有任何基于时间的测量点。能够从MySQL收集到的服务器操作的数据 大多是show status计数器的形式,这些计数器统计的是某种活动发生 的次数。这也是我们最终决定创建Percona Server的主要原因,Percona Server从版本5.0开始提供很多更详细的查询级别的测量点
  • 虽然理想的性能优化技术依赖于更多的测量点,但幸运的是,即使 系统没有提供测量点,也还有其他办法可以展开优化工作。因为还可以 从外部去测量系统,如果测量失败,也可以根据对系统的了解做出一些 靠谱的猜测。但这么做的时候一定要记住,不管是外部测量还是猜测, 数据都不是百分之百准确的,这是系统不透明所带来的风险
  • 举个例子,在Percona Server 5.0中,慢查询日志揭露了一些性能低 下的原因,如磁盘I/O等待或者行级锁等待。如果日志中显示一条查询 花费10秒,其中9.6秒在等待磁盘I/O,那么追究其他4%的时间花费在哪 里就没有意义,磁盘I/O才是最重要的原因

三、理解性能剖析

  • MySQL的性能剖析(profile)将最重要的任务展示在前面,但有时 候没显示出来的信息也很重要。可以参考一下前面提到过的性能剖析的 例子
  • 不幸的是,尽管性能剖析输出了排名、总计和平均值,但还是有 很多需要的信息是缺失的,如下所示:
    • 值得优化的查询(worthwhile query):性能剖析不会自动给出哪些查询值得花时间去优化。这把我们 带回到优化的本意,如果你读过Cary Millsap的书,对此就会有更 多的理解。这里我们要再次强调两点:第一,一些只占总响应时间 比重很小的查询是不值得优化的。根据阿姆达尔定律(Amdahl's Law),对一个占总响应时间不超过5%的查询进行优化,无论如 何努力,收益也不会超过5%。第二,如果花费了1000美元去优化 一个任务,但业务的收入没有任何增加,那么可以说反而导致业务 被逆优化了1000美元。如果优化的成本大于收益,就应当停止优 化
    • 异常情况:某些任务即使没有出现在性能剖析输出的前面也需要优化。比 如某些任务执行次数很少,但每次执行都非常慢,严重影响用户体 验。因为其执行频率低,所以总的响应时间占比并不突出。
    • 未知的未知:一款好的性能剖析工具会显示可能的“丢失的时间”。丢失的时 间指的是任务的总时间和实际测量到的时间之间的差。例如,如果 处理器的CPU时间是10秒,而剖析到的任务总时间是9.7秒,那么就 有300毫秒的丢失时间。这可能是有些任务没有测量到,也可能是 由于测量的误差和精度问题的缘故。如果工具发现了这类问题,则 要引起重视,因为有可能错过了某些重要的事情。即使性能剖析没 有发现丢失时间,也需要注意考虑这类问题存在的可能性,这样才 不会错过重要的信息。我们的例子中没有显示丢失的时间,这是我 们所使用工具的一个局限性
    • 被掩藏的细节:性能剖析无法显示所有响应时间的分布。只相信平均值是非常 危险的,它会隐藏很多信息,而且无法表达全部情况。Peter经常举 例说医院所有病人的平均体温没有任何价值(6)。假如在前面的性能 剖析的例子的第一项中,如果有两次查询的响应时间是1秒,而另 外12771次查询的响应时间是几十微秒,结果会怎样?只从平均值 里是无法发现两次1秒的查询的。要做出最好的决策,需要为性能 剖析里输出的这一行中包含的12773次查询提供更多的信息,尤其 是更多响应时间的信息,比如直方图、百分比、标准差、偏差指数 等
  • 好的工具可以自动地获得这些信息。实际上,pt-query-digest就在剖 析的结果里包含了很多这类细节信息,并且输出在剖析报告中。对此我 们做了简化,可以将精力集中在重要而基础的例子上:通过排序将最昂 贵的任务排在前面。本章后面会展示更多丰富而有用的性能剖析的例 子
  • 在前面的性能剖析的例子中,还有一个重要的缺失,就是无法在更 高层次的堆栈中进行交互式的分析。当我们仅仅着眼于服务器中的单个 查询时,无法将相关查询联系起来,也无法理解这些查询是否是同一个 用户交互的一部分。性能剖析只能管中窥豹,而无法将剖析从任务扩展 至事务或者页面查看(page view)的级别。也有一些办法可以解决这个 问题,比如给查询加上特殊的注释作为标签,可以标明其来源并据此做 聚合,也可以在应用层面增加更多的测量点,这是下一节的主题。

相关文章: