MySQL之性能剖析和Schema与数据类型优化(一)
性能剖析总结
- 1.衡量性能的核心指标是响应时间。
- 2.只有通过高质量、全方位及完整的响应时间测量才能有效进行性能优化工作。
- 3.通常建议从应用程序层面开始进行响应时间的测量。
- 4.大多数系统在全面性上存在不足,并且测不准的结果可能存在误差。
- 5.详尽的性能分析可能会产生大量数据供进一步研究。
- 6.剖析报告汇总了关键信息。
- 7.在系统中存在两类主要耗时操作:执行任务或等待处理结果。
- 8.优化与提升并非同一目标。
- 9.作为决策者,在采取行动前应谨慎评估直觉指引的价值。
总体而言,在解决性能问题的过程中首先要明确具体的问题所在,并根据具体情况选择合适的解决方案来应对各种挑战。如果你希望提升服务器的整体性能水平,则可以通过以下七个步骤实现目标:首先将所有相关的查询记录到日志中;接着利用pt-query-digest工具生成系统级的问题分析报告以获得整体性能状况概览。此外,在追查那些表现不佳的具体查询时,则可以通过分析相关性高的查询数据来获取有价值的信息来源。建议重点关注那些耗时最长、影响用户体验显著以及呈现出异常波动特征的行为模式等具有特殊性质的查询项;一旦识别出这些"异常"查询后,请深入分析pt-query-digest报告中包含的具体信息,并结合SHOW PROFILE等工具进一步优化运行机制。
如果找不到这些查询性能低下的原因,那么也可能时遇到了服务器级别的性能问题。这是,可以较高精度测量和回直服务器状态计数器的细节信息。如果通过这样的分析重现了问题,则应该通过同样的数据制定一个可靠的触发条件,来收集更多的诊断数据。多花费一点时间来确定可靠的触发条件,尽量避免漏检或者误报。如果已经可以捕获故障活动期间的数据,但还是无法找到其根本原因,则要么尝试捕获更多的数据,要么尝试寻求帮助。
我们无法完整地测量工作系统,但说到底它们都是某种状态机,所以只要足够细心,逻辑清晰并且坚持下去,通常来说都能得到想要的结果。要注意的时不要把原因和结果搞混了,而且在确认问题之前也不要随便针对系统做变动。
理论上纯粹的自顶向下的方法分析和详尽的测量只是理想的情况,而我们常常需要处理的是真实系统。真实系统是复杂且无法充分测量的,所以我们只能根据情况尽力而为。使用诸如pt-query-digest和MySQL企业监控器的查询分析其这样的工具并不完美,通常都不会给出问题根源的直接证据。但真的掌握了以后,已经足以完成大部分的优化诊断工作了。
Schema与数据类型优化
概述
优秀的逻辑架构与物理布局是高性能的基础。必须基于系统预期执行的查询语句来规划schema结构,在规划过程中需要综合考虑多方面的因素。例如,在规划时采用反范式的设计能够加速特定类型查询的速度;然而这可能导致其他类型查询效率降低。通过添加计数器与汇总表等方式可以有效提升性能;但其维护成本可能较高。此外 MySQL独有的特性及其实现细节对其性能表现有重要影响
选择优化的数据类型
MySQL支持大量数据类型供使用者选择,挑选恰当的数据类型对提升系统性能起着关键作用.无论存储何种类型的数据显示出最佳性能效果,以下几点建议将助您做出更优决策.
- 1.更好的通常更好
一般情况下,应该尽量使用可以正确存储数据更小的数据类型(例如只需要存0~200,tinyint unsigned更好)。更小的数据类型通常更快,因为它们占用更少的磁盘、内存和CPU缓存,并且处理时需要的CPU周期也更少。
但是要确保没有嘀咕需要存储的值范围,因为在schema中的多个地方增加数据类型的范围是一个非常耗时和痛苦的操作。如果无法确定哪个数据类型是最好的,就选择你认为不会超过范围的最小类型。(如果系统不是很忙或者存储的数据量不多,或者是在可以轻易修改设计的早期阶段,那之后修改数据类型也比较容易)
简单数据类型的操作通常消耗较少的CPU周期。例如,在大多数编程语言中整型运算的开销低于字符比较。这一现象主要源于由于字符集及排序规则(排序规则)的存在使得字符比较的复杂度高于整型比较。以下两个实例说明了这一观点:其一是在数据库管理中应该优先使用mySQL内置的数据类型(如date, time, datetime)而非字符串来存储日期与时间字段;其二是应优先选择整型变量来存储IP地址而非字符串。
- 3.尽量避免NULL
很多表都包含可为NULL(空值)的列,即使应用程序并不需要保存NULL也是如此,这是因为可为NULL是列的默认属性。通常情况下最好指定列为NOT NULL,除非真的需要存储NULL值。如果查询中包含可为NULL的列,对MySQL来说更难优化,因为可为NULL的列使得索引、索引统计和值比较都更复杂。可为NULL的列会使用更多的存储空间,在MySQL里也需要特殊处理。当可为NULl的列被索引时,每个索引记录需要一个额外的字节,在MyISAM里甚至还可能导致固定大小的索引(例如只有一个整数列的索引)变成可变大小的索引。
通常把可为NULl的列改为NOT NULL带来的性能提升比较小,所以(调优时)没有必要首先在现有schema中查找并修改掉这种情况,除非确定这回导致问题。但是,如果计划在列上键索引,就应该尽量避免设计成可为NULL的列。
当然也有例外,例如值得一提的时,InnoDB使用单独的位(bit)存储NULL值,所以对于稀疏数据(很多值为NULL,只有少数行的列有非NULL值)有很好的空间效率。但这一点不适用于MyISAM
在为列选择数据类型时,在建表阶段的第一步需要确定恰当的大类别的数据类型:整数型、字符型、日期型等。这通常是相当直接的过程。但是我们也会提到一些不太明显的特殊情况实例。
整数类型
有两种两类数字:integer(whole number)和real number(real number).当存储整型数据时,则可采用以下几种integer类型:TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT.这些类型的占用存储空间分别为8位至64位.它们所代表的数值范围则为从-2(N-1)到2(N-1)-1,其中N表示具体的位宽值.有符号与无符号的区别仅在于数值范围的不同而其他性能指标并无差异.因此根据具体的应用需求可以选择合适的integer宽度.这种选择将直接影响MySQL在内存与磁盘之间如何存储数据.对于大多数应用场景而言,int(1)与int(20)之间的区别并不大.因为即使是在32位的操作系统环境中,int(1)也会分配足够的宽度来保证数据的有效性.需要注意的是某些聚合函数例外情况会采用decimal或double进行计算
实数类型
实数是带有小数部分的数字。然而,它们不只是为了存储小数部分;也可以使用DECIMAL存储比BIGINT还大的整数。MySQL既支持精确类型,也支持不精确类型。
FLOAT和DOUBLE类型支持使用标准的浮点运算进行近似计算。如果需要直到浮点运算时怎么计算的,则需要研究所使用的平台的浮点数的具体实现。DECIMAL类型用于存储精确的小数。在MySQL 5.0和更高版本,DECIMAL类型支持精确计算。MySQL4.1及更早版本则使用浮点运算来实现DECIMAL的计算,这样做会因为精度损失导致一些奇怪的结果。在这些版本的MySQL中,DECIMAL只是一个"存储类型"。
因为CPU不支持对DECIMAL的直接计算,所以在MySQL5.0以及更高版本中,MySQL服务器自身实现了DECIMAL的高精度计算。相对而言,CPU直接支持原生浮点计算,所以浮点运算明显更快。
浮点和DECIMAL类型都可以指定精度。对DECIMAL列,可以指定小数点前后所允许的最大位数。这会影响列的空间消耗。MySQL5.0和更高版本将数字打包保存到一个二进制字符串中(每4个字节存9个数字)。例如DECIMAL(18,9)小数点两边将个存储9个数字,一共使用9个字节:小数点前的数字用4个字节,小数点后的数字用4个字节,小数点本身占1个字节。
MySQL5.0和更高版本中的DECIMAL类型允许最多65个数字。而早期的MySQL版本中,这个限制时254个数字,并且保存为未压缩的字符串(每个数字一个字节)。然而,这些(早期)版本实际上并不能在计算中使用这么大的数字,因为DECIMAL只是一种存储格式,在计算中DECIMAL会转换为DOUBLE类型。
有多种方法可以指定浮点列所需要的精度,这回使得MySQL悄悄选择不同的数据类型,或者在存储时对值进行取舍。这些精度定义时非标准的,所以建议只指定数据类型,不指定精度。
浮点类型在存储同样范围的值时,通常比DECIMAL使用更少的空间。FLOAT使用4个字节存储。DOUBLE只能用8个字节,相比FLOAT有更高的精度和更大的范围。和整数类型一样,能选择的只是存储类型;MySQL使用DOUBLE作为内部浮点计算的类型。
因为需要额外的空间和计算开销,所以应该尽量只在对小数进行精确计算时才使用DECIMAL——例如存储财务数据。但在数据量比较大的时候,可以高铝使用BIGINT代替DECIMAL,将需要存储的货币单位根据小数的位数乘以相应的倍数即可。假设要存储财务数据精确到万分之一,则可以把所有金额乘以一百万,然后将结果存储在BIGINT里,这样就可以同时避免浮点存储计算不精确和DECIMAL精确计算代价高的问题
