数据库是个比较大的话题,有各种各样数据库常见的关系型数据库如Mysql、oracle、非关系型数据库,还有图数据库等。数据库性能会跟许多部分有关联,从硬件底层存储设备、操作系统、数据库配置参数、数据库架构、数据库表结构、应用层面的连接池设置、以及SQL索引等。
对Mysql数据库进行分析,首先需要了解MySql的系统架构,如下图所示:
从这个架构图,来看Mysql系统架构分为应用层、MySql服务层、存储引擎层。
应用层,应用层是MySQL体系架构的最上层,它和其他client-server架构一样,主要包含:连接处理、用户鉴权、安全管理
MySQL服务层:该层是MysqlServer的核心层,提供了MysqlServer数据库所有逻辑功能
存储引擎层
存储引擎是MySQL中具体与文件打交道的子系统,也是MySQL最有特色的地方。MySQL区别于其他数据库的最重要特点是其插件式的表存储引擎。他根据MySQLAB公司提供的文件访问层抽象接口来定制一种文件访问的机制(该机制叫存储引擎)。
物理文件包括:redolog、undolog、binlog、errorlog、querylog、slowlog、data、index等
知道数据库架构后,在性能分析时候需要知道这些模块的功能及运行逻辑,明白一个具体的sql所需要经历的过程:一个sql首先经过ConnectionPool到达系统后,需要先进入Sqlinterface模块判断这个语句,是什么类型。然后通过Parser模块进行语法与语义检查,并生成相应的执行计划;接着到Optimizer模块进行优化,判断走什么索引,执行顺序等,然后就到Cache中找数据,如果Caches中找不到数据的话,就得通过文件系统到磁盘中进行寻找。
了解了mysql系统架构和mysql执行过程还不够,在进行性能分析时,需要找出mysql的问题所得先了解一些基础知识和相应的监控工具。
首先需要了解的两个Schema分别是information_schema和performance_schema,information_schema,它们保存了数据库中的所有表、列、索引、权限、配置参数、状态参数等信息。像我们常执行的showprocesslist;就来自于这个schema中的processlist表。performance_schema提供了数据库运行时的资源消耗情况,它以较低的代价收集信息,可以提供不少性能数据。
还有在分析mysql是需要知道的两个命令:showglobalvariables;和showglobalstatus;前一个用来查看配置的参数值,后一个用来查询状态值。不过这些命令只是简单的罗列信息,并没有统计分析,接下来我们介绍两个个比较好的监控工具。
全局分析:mysqlreport
showstatus输出的报告是用来计算性能瓶颈的参考数据,但是数据只是简单的罗列,不好一下子看出性能问题,而mysqlreport不像showstatus简单的罗列数据,而是对这些参考数据加以融合计算,整理成一个个优化参考点,然后就可以根据这个优化参考点的值以及该点的衡量标准,进行对应的调整。
一、linux环境下mysqlreport安装
步骤一:yum-yinstallperl-DBD-MySQL依賴包
步骤二:yum-yinstallperl-DBI#依賴包
步骤三:yum-yinstallmysqlreport
在linux系统上经过这三步就安装好了这个工具。接下来就可以对数据库运行状况进行分析了。
二、mysqlreport使用
使用比较简单,直接执行:
mysqlreport--usertesla--passwordxxx@2015--host127.0.0.1--no-mycnf--flush-status--outfile./result.txt就可以把数据库整体情况保存到当前目录中。
具体命令参数查看
mysqlreport—help三、mysqlreport结果分析:
数据库操作报表和查询排序报表
这个表反映数据库使用情况,608每秒操作量有点大,slow这个参数挺重要,只是因为这里设置的慢查询10s太长了,正常情况下尽量设置在1s左右,这块需要对db进行配置,把慢查询统计设置的短些。
DMS部分告诉我们这个数据库中各种SQL所占的比例,这个例子中,SELECT多,要做SQL优化的话,肯定优先考虑SELECT语句,才会起到立竿见影的效果。
这块的报表数据具有极大的参考性,一下就能看出问题的所在,这里的Scan(代表全表扫描)每秒48次执行全表扫描,实在是太多了,需要对语句进行修改,也是我们后面优化的重点内容。
InnoDB缓存池报表,InnodbBufferPoolsize定义了Innodb存储引擎的表数据和索引数据的最大内存缓存大小。这部分对MySQL来说很重要,这里使用已经达到100%这种情况下就必须要增加Innodb缓存池了。这里的Readhit达到92.57%,这个值越大越好,尽量达到100%这里的值与Innodbbuffer太小有关。
从这里可以看出数据连接还完全够用。
Waited表示有多少次查询需要等待表锁定;Immediate表示有多少次查询可以立即获得表锁定,同时后面还有一个比例
对数据库来说『等待』几乎可以肯定是一件很不好的事情,因此Waited的值应该要越小越好。最具有代表性的是第三个字段(Waited占所有tablelock的百分比)这里是0.00%,非常好,没有发送过表锁。
执行explain在sql分析时出现Usingtemporary的状态,这意味着查询过程中需要创建临时表来存储中间数据,我们需要通过合理的索引来避免它。另一方面,当临时表在所难免时,也要尽量减少临时表本身的开销,MySQL可以将临时表创建在磁盘(Disktable)、内存(Table)以及临时文件(File)中,显然,在磁盘上创建临时表的开销最大,所以我们希望MySQL尽量不要在磁盘上创建临时表,上面分析结果来看从临时表创建在磁盘(Disktable)和临时文件(File)上的量级来说,还是有点偏大了,所以,可以增大tmp_table_size。
其它全局信息可以查下资料
通过mysqlreport这个工具反应的结果,有以下问题需要去解决下:
总体数据库操作达到600多每秒,对于内网系统用户不太多,操作有点太频繁,看下能够减少不必要的数据库操作。
全表扫描48.5/s这块要分析下具体的sql写法
Innodb缓存占用使用100%,而且设置大小太小,需要增加缓存大小。
安装方法
安装:centos依赖包
yum-yinstallperl-TermReadKeyperl-Time-HiResperl-IO-Socket-SSL.noarchpt-query-digest--helppt-query-digest分析slow/binlog时产生的报告逻辑非常清晰,并且数据也比较完整。执行命令后就会生成一个报告,因为线网没开启slowlog日志,这里我们分析下线网binlog日志
使用方法
对binlog日志进行转换:
mysqlbinlog--no-defaults-vv--base64-output=DECODE-ROWSmysql-bin.000818>mysql-bin.000818.txtpt-query-digest--type=binlogmysql-bin.000818.txt>818.report.log筛选出全表扫描语句
profiling的操作步骤:查看详细执行计划
步骤一:setprofiling=1;//这一步是为了打开profiling功能
步骤二:执行语句//执行你从慢日志中看到的语句
步骤三:showprofiles;//这一步是为了查找步骤二中执行的语句的ID
步骤四:showprofileallforqueryid;//这一步是为了显示出profiling的结果
修改表结构增加索引:索引名一般是表名加字段名
showindexfromproject_permissions;ALTERtableproject_permissionsADDINDEXidex_project(project_id);ALTERtabletableNameADDINDEXindexName(columnName)createindex索引名on表名(字段名1,字段名2)分析:执行频率非常高的语句以及全表扫描1)
explainSELECTproject_id,modified_time,name,permissions,isGroupFROMproject_permissionsWHEREproject_id=2076;根据执行计划和查询条件分析,需要对project_id建立索引,建立索引后需要注意where条件中值的类型,这里需要把project_id改成字符串,mysql隐式的将数值类型转换成了字符串类型
2)
explainSELECTid,model_name,model_type,job_id,properties,gmt_create,owner,last_execution_model,gmt_modified,published,status,module_idfrommlstudio_modelwherejob_id=13788;数据库表记录9000条,没有增加索引,可以适当对job_id增加索引,也因为数据较小优先级比较低ALTERtablemlstudio_modelADDINDEXindex_model(job_id)有2倍性能能提升
3)
explainSELECTid,name,user_id,property,gmt_create,gmt_modified,appstatus,execution_infoFROMmlstudio_deployed_notebooksWHEREappstatusin(10,140,20,120)ORDERBYgmt_modifieddesc;分析及方案:数据库表记录200多条,没有增加索引,会全表扫描,优先级不太高,只不过property字段和execution_info信息数据比较大,建议如果property字段没有用到查询语句就不指定property
4)
explainselectid,algorithm_id,version,create_time,modify_time,module_id,shared,type,source_algorithm_version_idfromti_user_algorithm_versionwheremodule_id=813;解决方式:数据表记录目前较少数据库字段比较短
ALTERtableti_user_algorithm_versionADDINDEXindex_algorithm(module_id)5)
explainselectid,gmt_create,gmt_modified,name,type,description,checked,permission,user_id,nick_name,config_file_name,config_file_res,module_res,module_dependencies,job_type,user_coded,has_model,icon,module_jarsfrommlstudio_moduleswheremodule_res=0andtype>0andtype<1001andjob_type=2;数据记录不多,字段值相对都比较短,查询出来占据空间相对较小625条影响较小
6)
explainSELECTid,name,type,gmt_create,owner,gmt_modified,published,status,module_id,propertiesfrommlstudio_datasetwheremodule_id=229;数据记录不多,字段值相对都比较短,查询出来占据空间相对较小55条影响较小,对module_id加索引处理,查询很少可以不用处理
7)
explainselectalgorithm_idfromti_user_algorithm_favoritewhereuser_id=‘jianfehuang’andalgorithm_id=101;createindexalgorithmonti_user_algorithm_favorite(user_id,algorithm_id);解决方案:创建联合索引,索引后速度有一定提升,只会查出一行记录对缓存占用小。目前数据库记录196条
8)
explainselectcid,cname,cdesc,cicon,clevel,cparent,cvisible,group_concat(midorderbymname),sum(mpermission)aspublic_numfrom(selectmmc.idascid,mmc.nameascname,mmc.descascdesc,mmc.iconascicon,mmc.levelasclevel,mmc.parent_idascparent,mmc.visibleascvisible,mmc.order_numascorder,mm.idasmid,mm.nameasmname,mm.permissionasmpermissionfrommlstudio_module_categorymmcleftjoinmlstudio_modulesmmonmmc.id=mm.type)astgroupbycid,cname,cdesc,cicon,clevel,cparent,cvisibleorderbycorder;9)
selectqueuequota0_.idasid1_1_,queuequota0_.cpuascpu2_1_,queuequota0_.gmt_createasgmt_crea3_1_,queuequota0_.gpu_mapasgpu_map4_1_,queuequota0_.jizhi_business_flagasjizhi_bu5_1_,queuequota0_.memoryasmemory6_1_,queuequota0_.nameasname7_1_,queuequota0_.gmt_modifiedasgmt_modi8_1_,queuequota0_.uuidasuuid9_1_fromqueue_quotaqueuequota0_wherequeuequota0_.name=‘g_teg_teslaml_appgroup04’;分析全表扫描:目前数据表比较小,数据量才155条,对性能影响较小,如果预期后面数据量变大,考虑增加索引。
10)
selecttask0_.idasid1_0_,task0_.admin_groupasadmin_gr2_0_,task0_.alert_groupasalert_gr3_0_,task0_.business_flagasbusiness4_0_,task0_.gmt_createasgmt_crea5_0_,task0_.creatorascreator6_0_,task0_.descriptionasdescript7_0_,task0_.flagasflag8_0_,task0_.modifierasmodifier9_0_,task0_.nameasname10_0_,task0_.project_idasproject11_0_,task0_.propsasprops12_0_,task0_.typeastype13_0_,task0_.gmt_modifiedasgmt_mod14_0_,task0_.view_groupasview_gr15_0_fromtj_tasktask0_wheretask0_.project_idin(1157,1913,2078);分析全表扫描:目前太极任务数据表比较小,数据量才9条,对性能影响较小,如果预期后面数据量变大,考虑增加索引。
慢查询随着某个工程下工作流越多越慢,性能影响很大
selectflow_id,max(id*1000+status)%1000aslast_user_drive_statusfrommlstudio_execution_jobflowwhere(drive_type=1ordrive_typeisnull)andproject_idin(24529)groupbyflow_id存在问题扫描大量数据,拷贝到临时表,在执行文件排序。
修改为:
selectf.flow_id,f.statusfrommlstudio_model_flowtinnerjoinmlstudio_execution_jobflowfont.last_jobflow_id=f.idwheret.project_idin(24529)MySQL调优之innodb_buffer_pool_size大小设置
查询线上配置:
sql>showglobalvariableslike‘innodb_buffer_pool_size’;sql>showglobalstatuslike‘Innodb_buffer_pool_pages_data’;sql>showglobalstatuslike‘Innodb_page_size’;sql>showglobalstatuslike‘Innodb_buffer_pool_pages_total’;内网查询数据结果:
Innodb_buffer_pool_pages_total|8191Innodb_buffer_pool_pages_data|8116Innodb_page_size|16384innodb_buffer_pool_size|134217728调优参考计算方法:
val=Innodb_buffer_pool_pages_data/Innodb_buffer_pool_pages_total*100%val>95%则考虑增大innodb_buffer_pool_size,建议使用物理内存的75%val<95%则考虑减小innodb_buffer_pool_size,建议设置为:Innodb_buffer_pool_pages_data*Innodb_page_size*1.05/(102410241024)内网计算出来:8116/8190=99%需要加大这个数据
数据库配置修改:测试环境修改的/etc/my.cnf
slow_query_log=ONlong_query_time=12、Innodb缓存增大
innodb_buffer_pool_size=2G#设置2G3、临时表目前64M需要加大
pt-query-digest工具,可以从logs、processlist、和tcpdump来分析MySQL的状况,logs包括slowlog、generallog、binlog,可以借助分析结果找出问题进行优化。通过这两个工具可以在数据库配置层,对mysql进行相对比较优化的配置还可以找出性能比较慢的语句,通过profiling详细分析sql执行的过程进行优化。