此博文来自博主gaochaojs博主,如有疑问,请进入博主页面进行互动讨论!博文地址:http://jncumter.blog.51cto.com/812546/1620406前面博文中提到,流程后的实例信息可以通过统一入口查询,即高级查询(excel可以导出,并保留生成各种报表的接口)。但对于一些特殊的工作流程,比如转正、离职、考勤等,我们也提供了专门的查询模块。比如本文介绍的离职模块:离职模块分为三个部分,分别是新增离职信息、离职审批中、离职完成三个子模块。离职信息新增功能主要针对被动离职,即增加离职信息供单位说服、辞退或单方解除合同。这样的离职一旦保存,就可以认为离职完成了,所以不像approval中的离职查询逻辑很清楚,离职需要关联多表查询。在测试系统中测试时,我们发现直接执行终止离职查询sql,在数据量为17时,耗时1s左右,其实比较慢,但可以接受。正式系统上线后,约有400条离职数据。用户在前端简单的统计一下时间,大概需要十几秒的等待时间。用户体验已经很差了。拿出该查询sql,如下:SELECT*(SELECTDISTINCTleaveinfo.id,f_sqrgh,f_sqrbm,f_sqr,f_sqbmbm,f_sqbm,f_lxdhfj,f_sjhm,f_sqrq,f_rzrq,f_ndlzrq,f_qrlzrq,f_zw,f_gw,f_gwlx,f_gwcj,f_szdq,f_gzdd,f_lzyy,f_lzyyzs,f_yggxbmtjl,f_lzlx,f_inputtype,belongCompany,postDirection,techLevel,idCard,staffinfo.sex,staffinfo.birthday,exec.idAS'processExecutionId',exec.statusAS'processExecutionInprocess',exec.formDefineId,exec.processId,execDef,exec.tableName,process.`name`AS'processDefineName'FROMT_DYMC_20140625100255leaveinfoLEFTJOINt_per_staffinfostaffinfoONstaffinfo.staffId=leaveinfo.f_sqrghLEFTJOINt_bpm_process_executionexecONexec.pkValue=leaveinfo.idLEFTJOINt_bpm_process_defineprocessONprocess.id=exec.processDefineIdWHEREleaveinfo.f_sqrgh=staffinfo.staffIdAND(exec.`status`=2ANDleaveinfo.f_inputtype='FLOW'ORleaveinfo.f_inputtype='MANUAL'))allDataLEFTJOINt_sys_usersysUserONallData.f_sqrgh=sysUser.staffId这是一个分页查询,查询所有结果的个数,如下:SELECTCOUNT(DISTINCTallData.id)FROM(SELECTDISTINCTleaveinfo.id,leaveinfo.f_sqrghFROMT_DYMC_20140625100255leaveinfoLEFTJOINt_per_staffinfostaffinfoONstaffinfo.staffId=leaveinfo.f_sqrghLEFTJOINt_bpm_process_executionexecONexec.pkValue=leaveinfo.idLEFTJOINt_bpm_process_defineprocessONprocess.id=exec.processDefineIdWHEREleaveinfo.f_sqrgh=staffinfo.staffIdAND(exec.`status`=2ANDleaveinfo.f_inputtype='FLOW'ORleaveinfo.f_inputtype='MANUAL'))allDataLEFTJOINt_sys_usersysUserONallData.f_sqrgh=sysUser.staffId在测试系统中,我们用17条数据测试了两条sql,耗时不到0.5s。但在正式系统中,当测试数据量为398条时,***项的执行时间约为9.313s,第二项耗时约为4.341s。显然,398条数据只需要查询10多秒,这显然超出了用户的承受能力,极大地影响了系统的性能,也大大降低了用户体验。首先我们来梳理一下SQL。以第一个入口为例,我们关联了多张表进行查询,这多张表是否有必要,是否可以从逻辑上进行优化。我们查询的主表是离职信息表,它关联了文件、操作、流程定义三张表。最后添加上文提出的数据权限限制,关联到user表。对于关联档案,我们希望通过档案查询离职人员信息。对于关联操作表的信息,我们希望找出当前的handler和当前的处理阶段。关于流程定义表,我们要找出流程定义的名称。经过分析,我们首先发现这条sql是工程师从高级查询中复制过来的,因为高级查询是应用于所有进程的,需要通过processDefineId查询进程名,而我们的离职查询就是查询的离职进程,无需关联张表查询。我们去掉这个关联,作为processDefineName直接返回“离职流程”。去掉这个关联后,SQL的效率有提升,但提升不明显。从逻辑上来说,我们没有优化的余地。所以希望从数据库技术的角度来优化一下。在开始优化之前,先看一下当前语句使用过的优化技术(对于非专业的DBA,首先能想到的优化一般是索引),mysql中提供了explain查询mysql如何使用用于处理选择语句和连接表的索引。接下来我们看看查询语句在优化之前有没有用到什么优化技术,用了哪些优化技术。优化前,我们已经有了archives和users两张表的staffid索引。查询索引的sql语句如下:showindexfromt_per_staffinfo如下图:还有user表的索引:查询语句中有两张表:t_bpm_process_define和t_bpm_process_execution,我们为其创建索引,希望能够添加索引后提高查询效率:ALTERTABLEt_bpm_process_executionADDINDEXpkValue_index(pkValue);同样,我们也为statusstatus和t_bpm_process_define添加了索引。下面我们使用explain来看一下我们当前的查询语句,如下图所示:基于上图,我们看一下使用explain查到的信息中各列的含义。顾名思义,我们可以看出table是指查询的表名,type是指使用哪种类型的连接(连接类型从好到坏分别是const、eq_reg、ref、range、index、all),possible_key表示表中可能使用的索引,key指的是表中的索引。查询中实际使用的索引(如果值为null表示不使用索引,mysql在极少数情况下会使用未优化的索引,但也可以使用usingidex强制使用索引),key_len表示索引长度(在不损失准确性的前提下,长度越短越好),ref是索引在哪一列使用,rows是mysql认为请求返回数据需要校验的数据长度,extra表示附加有关分析查询的信息。通过分析Extra,我们可以看到哪些索引需要优化,如何优化。Extra的值包括Distinct,NotExist,Rangechechedforeachrecord,usingfilesort,usingtemporary,Usingindex,whereused,system,const,eq_ref,ref,index,all。当usingfilesort(需要额外的排序步骤)和usingtemporary(需要一个临时表来存储中间结果)出现时,就意味着查询需要优化。从图中我们可以看到,有些索引还需要进一步优化,但是我们的查询速度已经从近10s降到了0.088s。对于非专业的DBA来说,这个优化已经算是成功了。优化到这里就结束了,我会和DBA进一步沟通进一步优化使用临时的,将优化进行到底。接下来讲一下查询的基础理论,索引对查询的改进和索引的基础知识。对于MySQL的查询机制,在MySQL手册(7.2.1)中有这样的描述:“ThetablesarelistedintheoutputintheorderthatMySQLwouldreadthemwhileprocessingquery.MySQLresolvesalljoinusingasingle-sweepmulti-join方法,即MySQL从第一个表中读取一行,然后在第二个表中找到匹配的行,然后在第三个表中,以此类推。当所有表都处理完后,MySQL输出选择的列并回溯遍历表列表,直到找到一个有更多匹配行的表。从该表中读取下一行,然后继续处理下一个表。从第三句开始做一个简单的翻译:Mysql从**第一张表中读取***行数据,然后在第二张表中找到匹配的行,再找到第三张表,以此类推。当所有的表都处理完后,Mysql输出选中的列,然后回溯表列表,直到出现匹配更多行的表。从此表中读取下一行,然后转到下一个表。这个关联查询过程的关键是从上一张表中查询当前表的内容。了解了从上表查询当前表的原理后,创建索引的目的就是告诉MySQL如何直接查询下一张表的数据,以及如何按照要求的顺序连接下一张表。上面我们也介绍了查看和创建索引的语句。想了解更多其他操作方法,可以查看索引的一些基础知识。
