关于一个用户迁移数据库前后的性能差异分析

一个用户工单:数据从ECS迁移到RDS,相同的语句,查询性能下降了几十倍。而实际上RDS这个实例在内存上的配置与原来ECS上的实例相当。

本文简单说明这个case的原因及建议。

用户反馈性能变慢的语句为 (修改了真实表名和列名)
select count(1) from HR hr join H h on h.hid = hr.hid
join A e on e.aid = h.eid
join A t on t.aid = e.pid
join A c on c.aid = t.pid
join A p on p.aid = c.pid
left join U u on u.uid = hr.uId
left join E emp on emp.eid = hr.oid
where ( hr.s in (1,2,3,4) and hr.cn = 0 );

背景

MySQL执行语句过程中涉及到两大流程:优化器和执行器。其中优化器最主要的任务,是选择索引和在多表连接时选择连接顺序。在这个case中,join顺序的选择影响了执行性能。

确定join执行顺序就需要估算所有join操作的代价。默认配置下MySQL会估算所有可能的组合。

MySQL Tips: MySQL里限制一个查询的join表数目上限为61.

对于一个有61个表参与的join操作,理论上需要61!(阶乘)次的评估。当然这是最坏情况下,实际上减枝算法会让这个数字看起来稍微好一点,但是仍然很恐怖。

在多表join的场景下,为了避免优化器占用太多时间,MySQL提供了一个参数 optimizer_search_depth 来控制递归深度。
这个参数对算法的控制可以简单描述为:对于所有的排列,只取前当前join顺序的前optimizer_search_depth个表估算代价。举例来说,20张表的,假设optimizer_search_depth为4,那么评估次数为20*19*18*17,虽然也很大(因此我们特别不建议这么多表的join),比20!好多了。

于是optimizer_search_depth的选择就成了问题。

MySQL Tips: MySQL中optimizer_search_depth默认值为62.也就是说默认为全排列计算。

这样能够保证得到最优的执行计划,只是在有些场景下,决定执行计划的时间会远大于执行时间本身。

量化分析

在ECS上,是用户自己维护的MySQL,没有设置optimizer_search_depth,因此为默认的62。在RDS上,我们的配置是4。 分析到这里大家能猜到原因是RDS配置的4导致没有得到最优的执行计划。

下图是optimizer_search_depth=4时的explain结果(隐藏了业务相关的表名、字段名)

 

下图是optimizer_search_depth=62是的场景,当然这个case的join表是8个,因此62和8在这里是等效的。

 

从图1可以看到,由于optimizer_search_depth=4,优化器认为自己选择了最优的join顺序(22039*1*1*1),优于(41360*1*1*1),而实际上后者才是全局最优。

关于实践

可配置的参数提供灵活性的同时,也提出一个头疼的问题:应该设置为多少才合适。 实际上当用户执行一个多表join的时候,对这个语句的整体RT的期望值就不会高。因此可以先定义一个预期,比如优化器决策join顺序的时间不能超过500ms。 用户规格与cpu相关,因此这个只能是建议值。

用户实践

实际上更重要的是对于用户来说:

1) 当出现实例迁移后,多表join执行结果差异较大的时候,要考虑调整这个值。该参数是允许线程单独设置,因此对于应用层来说,每个连接应该都能得到一个较优的值。

2) 反过来,当设置为默认的optimizer_search_depth=62时,我们我们如何评估我们这个设置是否过大?
MySQL Tips:MySQL profiling 可以用于查看各执行环节的消耗时间。

如下是笔者构造的一个60个表join查询的查询,使用profiling查看执行环节消耗的过程。
set profiling=1;
set optimizer_search_depth=4;
explain select …….
show profile for query 2;
结果如图

 

继续执行
set optimizer_search_depth=40;
explain select …….
show profile for query 4;

 

小结

1)根据机器配置估算一个可接受的时间,用于优化器选择join顺序。

2)用profiling确定是否设置了过大的optimizer_search_depth。

3)业务上优化,尽量不要使用超过10张表的多表join。

4)PS:不要相信银弹。MySQL文档说明设置为0则表示能够自动选择optimizer_search_depth的合理值,实际上代码上策略就是,如果join表数N<=7,则optimizer_search_depth=N+1,否则选N.

时间: 2024-10-03 16:01:57

关于一个用户迁移数据库前后的性能差异分析的相关文章

android-oracle同一数据库中怎样将一个用户下的表导入或复制到另一个 用户中

问题描述 oracle同一数据库中怎样将一个用户下的表导入或复制到另一个 用户中 ** oracle同一数据库中怎样将一个用户下的表导入或复制到另一个 用户中** 解决方案 oracle把一个用户的表数据复制到另一个用户oracle把一个用户下数据库对象的某个权限赋给另一个用户Oracle当前数据库用户访问另一个用户的表 解决方案二: exp owner=a imp fromuser=a touser=b 解决方案三: exp file=路径 full=y owner=用户1 imp fromu

数据库xxx已打开,并且一次只能有一个用户访问。 (Microsoft SQL Server,错误: 924)

操作数据库失败,提示如下错误: 数据库xxx已打开,并且一次只能有一个用户访问. (Microsoft SQL Server,错误: 924) 重启数据库问题仍然存在.可执行以下sql解决: USE master; GODECLARE @SQL VARCHAR(MAX); SET @SQL='' SELECT @SQL=@SQL+'; KILL '+RTRIM(SPID) FROM master..sysprocesses WHERE dbid=DB_ID('库名'); EXEC(@SQL);

数据库、设计-类似于 论坛 发表 评论、回复功能,每一个用户显示昵称, 如果是好友则 显示备注 怎么设计数据库==

问题描述 类似于 论坛 发表 评论.回复功能,每一个用户显示昵称, 如果是好友则 显示备注 怎么设计数据库== 我想到的方式有.冗余数据.或者每次查询一次.缓存.但是备注修改之后 都会涉及到更新,更新 表的数据 太多.效率是一个问题.??求解 解决方案 可以给用户信息建立冗余的字段,或者放在内存缓存中.

数据库怎么设计一个房间包含多个用户,一个用户又可以归属多个房间

问题描述 数据库怎么设计一个房间包含多个用户,一个用户又可以归属多个房间 对数据库也不是很懂,请教!!! 数据库怎么设计一个房间包含多个用户,一个用户又可以归属多个房间 解决方案 这就是多对多关系嘛.两个表各自有一个主键,有一个外键.然后关联起来. 再不会,随便找一个数据库,比如northwind,里面就有,看一下. 解决方案二: 楼上说的很对,多对多关系 解决方案三: 建三张表,房间表,用户表,中间表.建他们的主键放在中间表关联起来.

java web工程中一个dao只有一个实例访问数据库对性能的影响

问题描述 就是同一个dao实现只会实例化一个,每次访问数据库的时候都是用的同一个实例,这样对性能会不会有什么影响,不考虑线程安全. 解决方案 解决方案二:每一次访问都new了一个新的dao,对性能会不会有影响解决方案三:dao一般不会有带状态的成员变量不会引发线程安全问题.解决方案四:该回复于2010-05-15 14:14:18被版主删除

impdp在同一个数据库中将一个用户下的对象复制到另一个用户下

比如要将ybht_hs用户下的对象复制到另一个用户ybht_ty下 那么在ybht_hs用户下创建一个public database link create public database link tolink connect to ybht_hs identified by "hs" using '(DESCRIPTION =     (ADDRESS_LIST =       (ADDRESS = (PROTOCOL = TCP)(HOST =10.138.129.4)(PORT

如何保持Oracle数据库的优良性能

oracle|数据|数据库|性能 作者:Brent Oracle数据库以其高可靠性.安全性.可兼容性,得到越来越多的企业的青睐.如何使Oracle数据库保持优良性能,这是许多数据库管理员关心的问题,根据笔者经验建议不妨针对以下几个方面加以考虑. 一.分区 根据实际经验,在一个大数据库中,数据空间的绝大多数是被少量的表所占有.为了简化大型数据库的管理,改善应用的查询性能,一般可以使用分区这种手段.所谓分区就是动态表中的记录分离到若干不同的表空间上,使数据在物理上被分割开来,便于维护.备份.恢复.事

SQL Server数据库备份的性能优化

一.选择合理的备份时机. 虽然说,SQL Server数据库在联机或者活动状态,也可以进行备份.但是,一般情况下,笔者不建议这么做.因为在数据库活动的时候进行备份的话,一方面会增加备份的时间;另一方面,因为备份作业占用了一定的硬件资源,会对数据库的访问性能产生比较大的影响,特别是并发性访问. 所以,在数据库备份的时候,数据库管理员应当尽量减少SQL Server中的当前活动.对于大部分企业来说,一般数据库活动的高发期在白天的八个小时.故从理论上说,除了这八个小时外,对数据库进行备份的话,可以把这

使用RMAN迁移数据库到异机

        迁移数据库的方法有多种,较为常用的则是使用RMAN来迁移.使用RMAN迁移数据库属于数据库的物理备份与恢复范畴,整个过程中数据库的相关信息是完整地镜像.因此,基于此种方式还原恢复的数据库用于测试会使得与真实的生产环境差异相对较小.本文描述了使用RMAN来还原Oracle 10g数据库的过程.   一.主要步骤     1.备份数据库     2.ftp备份到目的服务器     3.为目标数据库创建项目目录     4.为目标数据库创建pfile或spfile(使用RMAN还原或复