注意:以下文档只适用于TOP接口,请谨慎使用!

文档中心 > 解决方案中心

随着ISV系统业务量的增,商家订单越来越多,数据库的规模越来越大,对性能要求也越来越高,因此RDS数据库应用优化技术显得更加重要,数据库系统能否正常、高效地运行倍受ISV和商家关注。本方案以数据库性能优化的基本原则为出发点,对数据库性能优化进行了分析,阐述了影响数据库性能的主要因素,并就数据库优化典型案例进行了探讨。

CPU优化方法

CPU使用率高通常是由于慢SQL 导致,这里的慢SQL包括高并发下的全表扫描,内存排序,磁盘排序,锁争用和锁等待等。

用户可以通过show processlist查看当前正在执行的sql。当执行完show processlist后出现大量的语句,通常其状态出现sending dataCopying to tmp tableCopying to tmp table on diskSorting result, Using filesort 都是sql有性能问题在下面有具体案例分析

1sending data表示:sql正在从表中查询数据,如果查询条件没有适当的索引,则会导致sql执行时间过长;

2Copying to tmp table on disk:出现这种状态,通常情况下是由于临时结果集太大,超过了数据库规定的临时内存大小,需要拷贝临时结果集到磁盘上,这个时候需要用户对sql进行优化;

3Sorting result, Using filesort:出现这种状态,表示sql正在执行排序操作,排序操作都会引起较多的cpu消耗,通常的优化方法会添加适当的索引来消除排序,或者缩小排序的结果集。

4InnoDB产生死锁会导致CPU消耗高,当系检测到死锁,Innodb 会选择产生死锁的两个事务中较小的事务来回滚,而让另外一个较大的事务成功完成;调整锁等待超时参数:innodb_lock_wait_timeout

5)子查询导致CPU消耗高,在mysql的常见的5.05.15.5版本中都存在较大风险,使用不当则会造成严重的性能问题,建议将子查询改为关联的形式

连接数优化方法

如果出现连接数报警的时候,可以通过show processlist查看数据库中正在运行的连接。一般sql执行慢或者某个sql持有锁导致其他sql等待,两种情况都会引发会话堆积产生报警。

1.优化慢查询

2 .SQL死锁了,持有锁的sql 导致连接堆积,需要根据业务是否允许,kill掉持有锁的会话;

3. 连接数用满,并且不自动释放,可以在RDS控制台重启一下实例。

4..高并发的情况下,少使用长连接

5.设置一个短的超时时间,让短连接尽快的自动关闭:wait_timeout

6myisam存储引擎的表,如果该表上面的查询没有返回的话,会堵塞该表的写入,从而导致连接堆积。将表的存储引擎转为innodb

 

RDS空间优化方法

1)临时空间快速增长,消耗RDS空间

一些查询语句(order by, group by)会创建临时表。用explain查看select语句的执行计划,如果extra列显示“using temporary,即使用了内部临时表。使用临时表会消耗磁盘空间,同时性能也比较低,在实际应用中应该尽量避免临时表的使用。

常见的方法有:

2)日志文件快速增长

数据库的更新写入压力过多:updateinsertdelete,会导致日志容量急增

3)数据库采用了大字段:varchar(8000),text,blob,clob(sqlserver/mysql),大字段很消耗空间。

4)系统文件空间

长时间没有提交事务,同时数据库中有大量的更新,插入,删除 ,导致innodb创建大量的undo来维护一致性;

 

常见的方法有:

1.控制台一键清理binlogRDS会定期将用户的日志进行清理并上传到OSS

2.将大字段存放到OSS,程序里只提供大字段数据所在位置的

3. 创建索引:在ORDER BY或者GROUP BY的列上创建索引;

4. 控制临时文件目录的最大值,超过则kill掉查询。现在的MySQL5.6已经支持

5 分拆很长的列:一般情况下,TEXTBLOB,大于512字节的字符串,基本上都是为了显示信息,而不会用于查询条件, 因此表设计的时候,应该将这些列独立到另外一张表。

如果表的设计已经确定,修改比较困难,那么也可以通过优化SQL语句来减少临时表的大小,以提升SQL执行效率。

6升级容量空间,RDS支持单独升级磁盘空间,最大容量支持到数T

7.optimize  table +表名,手动输入命令操作收缩数据库,在业务低峰期操作,会锁住整张表。

RDS应用架构:

1.RDS升级到5.6版本,实行读写分离,减轻数据库的性能压力。

2. 将离线分析计算的数据迁移到ODPS进行离线分析,ODPS间隔时间会逐步改短,提高分析数据的实时性

3. ECSRDS之间,部署OCS,缓存RDS的读数据,同时减轻RDS的读性能压力

RDS CPU优化案例

出现sending data 导致CPU高的情况:

| 2833185 | sanwenba | 10.241.91.81:45964 | sanwenba | Query

| 1 | Sending data | SELECT * FROM `www_article` WHERE CONCAT(subject,description) like '%??%' ORDER BY aid desc LIMIT 75,15

性能sql

SELECT * FROM `www_article` WHERE CONCAT(subject,description) like'%??%' ORDER BY aid desc LIMIT 75,15

这种sql是典型的sql分页写法不规范的情况,需要将sql进行改写:

select * from www_article t1,(select aid from www_article where CONCAT(subject,description) like '%??%' ORDER BY aid desc LIMIT 75,15)t2 where t1.aid=t2.aid;

注意这里的索引需要改用覆盖索引:aid+ subject+description

索引优化

SQL       SELECT order_id, order_sn

FROM order_info FORCE INDEX (shipping_time)

WHERE order_status = 1

         AND shipping_status = 0

         AND is_send = 0

         AND is_locked = 0

         AND shipping_time <= 1419632103

ORDER BY is_emergency DESC, update_time DESC

建议:    

添加索引:ALTER TABLE order_info ADD INDEX IDX_IS_SH_IS_UP (IS_SEND,SHIPPING_STATUS,IS_EMERGENCY,UPDATE_TIME)

 

SQL       DELETE FROM task_process

WHERE task_id = '1800067'

建议:     添加索引:ALTER TABLE task_process ADD INDEX IDX_TASK_ID (TASK_ID)

 

SQL       SELECT id, order_sn, upload_request_flag, upload_response_flag

FROM api_wms_trade USE INDEX (lianhe)

WHERE id > 0

         AND ckdm IN ('')

         AND order_type = 'order_info'

         AND upload_response_flag = 0

         AND cancel_request_flag = 0

         AND wms_order_flow_end_flag = 0

ORDER BY id

LIMIT 100

建议:    

添加索引:ALTER TABLE api_wms_trade ADD INDEX IDX_CK_UP_WM_OR (CKDM,UPLOAD_RESPONSE_FLAG,WMS_ORDER_FLOW_END_FLAG,ORDER_TYPE)

 

SQL       SELECT ld.id AS ld_id, lg.id AS lg_id

FROM lsxhdlk_goods lg

         INNER JOIN lsxhdlk lk ON lg.p_id = lk.id

         INNER JOIN lsxhd ld ON lk.p_id = ld.id

WHERE lg.is_ft = 0

         AND ld.ywrq >= 1341504000

LIMIT 50

建议:     添加索引:ALTER TABLE lsxhdlk_goods ADD INDEX IDX_IS_FT_P_ID (IS_FT,P_ID)

 

SQL

SQL      select 'data' as fnodepath , case when order_type = 0 then '1' when order_type = 1 then '0' end as auart , b.sddm as kunnr , b.sdmc as name1 , a.djbh as bstkd , c.brand_code as zbbrand , '---' as posnr , '---' as ean11 , '---' as lgort , '---' as kbetr , '---' as wmeng from lsxhrb a left join shangdian b on a.sd_id = b.id left join brand c on a.brand_id = c.brand_id where djbh = :1 union all select 'data\\items' as fnodepath , '---' as auart , '---' as kunnr , '---' as name1 , '---' as bstkd , '---' as zbbrand , cast ( ( @mycnt := @mycnt+1 ) as char ( 10 ) ) as posnr , d.barcode as ean11 , c.ckdm as lgort , cast ( j.zk as char ( 10 ) ) as kbetr , cast ( sum ( b.sl ) as char ( 10 ) ) as wmeng from lsxhrb a left join lsxhrbmx b on a.id = b.p_id left join cangku c on a.ck_id = c.id left join goods_barcode d on b.goods_id = d.goods_id and b.color_id = d.color_id and b.size_id = d.size_id left join goods e on b.goods_id = e.goods_id left join shangdian f on a.sd_id = f.id left join dttjdmf1 h on a.sd_id = h.sd_id left join dttjdmp j on h.djbh = j.djbh and b.goods_id = j.goods_id where a.djbh = :2 group by d.barcode , c.ckdm union all select 'data\\items' as fnodepath , '---' as auart , '---' as kunnr , '---' as name1 , '---' as bstkd , '---' as zbbrand , cast ( ( @mycnt := @mycnt+1 ) as char ( 10 ) ) as posnr , '运费' as ean11 , b.ckdm as lgort , cast ( shipping_fee as char ( 10 ) ) as kbetr , 0 as wmeng from lsxhrb a left join cangku b on a.ck_id = b.id where a.djbh = :3 and shipping_fee <> :4

建议:     严重】扫描行与发送行的比是359514,并且使用了聚合函数,该SQL索引过滤性不好,影响服务器性能。

 

SQL       select a.* , now ( ) as createtime from order_info a left join cangku b on a.ck_id = b.id , z_qyrq where ( a.order_status = :1 and shipping_status = :2 and is_send = :3 and process_status = :4 and is_separate = :5 ) and b.ckmc like :6 and a.add_time > z_qyrq.qyrq and exists ( select id from api_wms_trade where upload_response_flag in ( :7 , :8 ) and upload_request_flag = :9 and order_type = :10 and cancel_request_flag = :11 and wms_order_flow_end_flag = :12 and order_sn = a.order_sn )

建议:     严重】扫描行与发送行的比是3738355,需要注意like可能无法使用索引,请优化表结构和SQL语句。

 

SQL       select lsxhd.lylx , order_id , invoice_no , shipping_name from lsxhd , lsxhdlk where lsxhd.id = lsxhdlk.p_id and ( lsxhdlk.back_status = :1 or ( lsxhdlk.back_status = :2 and ( back_errmsg like :3 or back_errmsg like :4 or back_errmsg like :5 ) ) ) and lsxhd.sd_id = :6 order by lsxhdlk.back_status , lsxhdlk.add_time limit :7

         严重】扫描行与发送行的比是744,需要注意like可能无法使用索引,请优化表结构和SQL语句。

建议:平均发送行1172,返回行数过多,请考虑在低峰时执行这类语句,以减少对其他查询的影响。

 

SQL       select order_id , order_sn from order_info force index ( shipping_time ) where order_status = :1 and shipping_status = :2 and is_send = :3 and is_locked = :4 and shipping_time <= :5 order by is_emergency desc , update_time desc

         建议:【 严重】扫描行与发送行的比是2053460,并且使用了force index,该SQL索引过滤性不好,影响服务器性能,请确认force index是否合理。

警告】您的SQL语句锁行过多,可能堵住其他更新语句

 

SQL       delete from task_process where task_id = :1

建议:     【警告】您的SQL语句锁行过多,可能堵住其他更新语句

 

降低CPU的压力,Sql优化是性能优化的关键一步,直影响用户的使用,也是最容易优化的步骤,往往效果最直接。RDS由于有资源的隔离,不同的实例规格拥有的iops能力不同,比如新1型提供的iops150个,也就是每秒能够提供150次的随机磁盘io操作,所以如果用户的数据量很大,内存很小,由于iops的限制,一条慢sql就很有可能消耗掉所有的io资源,而影响其他的sql查询,对于数据库来说就是所有的sql需要执行很长的时间才能返回结果,对于应用来说就会造成整体响应的变慢。

 

RDS连接数优化案例

[root@******.aliyun.com ~]# mysql -uroot -h127.0.0.1 –P****** -e "show processlist"|wc -l

1262

可以看到该实例已经有1262 个连接

3、排查是什么动作占用了这些连接:

[root@******.aliyun.com ~]# myql -uroot -h127.0.0.1 –P****** -e "show full processlist">/tmp/1.log

root@******.aliyun.com # more /tmp/1.log

615083 my_db ******:54115 my_db Query 100 Sending data

INSERT INTO tmp_orders_modify (oid, tid, seller_id, `status`, gmt_create, gmt_modified)

SELECT oid, tid, seller_id, `status`, gmt_create, gmt_modified

FROM sys_info.orders WHERE

gmt_modified < NAME_CONST('v_last',_binary'2012-12-24 10:33:00' COLLATE 'binary') AN

D gmt_modified >= NAME_CONST('v_curr',_binary'2012-12-24 10:32:00' COLLATE 'binary')

621564 my_db 223.4.49.212:46596 my_db Query 3890 sorting result

insert into tmp_trades(sid, d, h, tc, tm, tp, ic, new_tp, old_tp)

select a.seller_id as sid,

…………..

from orders_1 as a where seller_id =1 and is_detail = '1'

and created < date_format('2012-12-24 10:35:00', '%Y-%m-%d %H:00:00')

and gmt_create < date_format('2012-12-24 10:40:00', '%Y-%m-%d %H:%i:00')

and gmt_create >= date_format('2012-12-24 10:35:00', '%Y-%m-%d%H:%i:00')

group by d, h

order by d

……………….此处省略其他sql

4、分析连接占用的原因:

可以看到数据库中有长时间没有执行完成的sql,一直占用着连接没有释放,而应用的请求一直持续不断的涌入数据库,这个时候数据库的连接很快就被使用完;所以这个时候需要排查为什么这些sql 为什么长时间没有执行完毕,是索引没有创建好,还是sql执行耗时严重。

第一条sql

INSERT INTO tmp_orders_modify (oid, tid, seller_id, `status`, gmt_create, gmt_modified)

SELECT oid, tid, seller_id, `status`, gmt_create, gmt_modified

FROM sys_info.orders WHERE

gmt_modified < NAME_CONST('v_last',_binary'2012-12-24 10:33:00' COLLATE 'binary') AN

D gmt_modified >= NAME_CONST('v_curr',_binary'2012-12-24 10:32:00' COLLATE 'binary')

是用户从sys_info 数据库中拉取订单到自己的业务库中那个,但是在orders 表上没有gmt_modified 的索引,导致了全表扫描;

第二条sql

看到这条sql 正在进行sorting 排序,为什么导致sql 长时间sorting,通常情况下为排序的结果集太大导致排序不能在内存中完成,需要到磁盘上排序,进而导致了性能的下降;解决的办法就是降低排序的结果集,常用的手段是利用索引的有序性,消除排序,或者建立适当的索引减小结果集

Alter tale order_1 add index ind_order_gmt_create(gmt_create)

(该用户对orders 进行了分表,大概有50 多张分表需要添加gmt_create 字段的索引);

5、经过上面两步的优化后,用户实例恢复正常:connection 情况,可再次登陆RDS控制台查看连接数。

 

RDS磁盘优化案例:

CREATE TABLE `class_meta` (

`class_name` varchar(128) NOT NULL COMMENT ‘类名’,

`class_desc` varchar(2048) default COMMENT ‘类的描述’,

`class_status` char(20) default test1 COMMENT test1,test2,

PRIMARY KEY (`class_name`),

UNIQUE KEY `cm_cn_uk` (`class_name`),

KEY `cm_cd_ind` (`class_desc`(767)),

KEY `cm_cs_ind` (`class_status`),

KEY `cm_cdcn_ind` (`class_desc`(767),`class_name`)

) ENGINE=InnoDB DEFAULT CHARSET=latin1 COMMENT=meta信息’;

通过上面的表结构能看到如下地方不合适

1、主键与唯一索引明显重复,索引cm_cd_ind与索引cm_cdcn_ind索引重复(这种情况经常出现,大家留意下)

2cm_cs_ind如果两个状态分布均匀也明显不合适建索引

3class_desc由于是描述性质的,也不合适建索引

4、最好以自增做为主键,可以减少整表的空间

5class_status列明显可以用tinyint来存,可以省下19个字节

2、存储内容上

1) 是否将图片、视频、音乐等大数据存储在表中?(表里最好只保留路径而不是实际的文件内容)

3、数据保留上

1)是否有已过期而未删除的数据?(对于无效数据及时清理或者进行历史归档)

4、后期维护上

1)是否对经常删除的表进行维护(optimize table)

建议:

1、在性能要求不高的case(并发不太高),可以考虑使用压缩表。一般压缩率在30%-70%之间,收益非常可观。

2、对于删除非常频繁的表要定期进行优化,使表中碎片减少。提高查询、写入的性能。

3、在表结构设计上,一定要发扬“斤斤计较”的精神,能用1个字节表示的坚决不用2个字节。

4、尽量减少大字段的使用。

当你的数据级到T或者P的时候,哪怕多省几个字节都是非常可观的,给大家简单算笔账,如果我们将一张5亿条记录的表,字段从100个字节降到60个字节(应该很容易做到吧),那么不算上索引将节约大约18G的空间。

4.Varchar\nvarchar\varbinary\text\ntext\image等大字段优化

SQL Server使用varchar(max)/nvarchar(max)varbinary(max)text/ntextimage这些大字段,可能导致数据库日志飚升,达到或超过数据文件大小,导致实例被锁定。实际案例中,有的客户1小时增长超过100G。经过改进,将大部分字段调小,该问题消除。建议:除了历史归档或文献资料类型的应用外,一般不需要用大字段来做存储。大字段的最大存储大小是 2^31-1 个字节 (2 GB),所以SQL Server需要用一种特别的方式来存储和操作它,其成本也就比普通字段高。而如果数据库使用了full模式,响应的日志量也就高很多了。

RDS性能好坏直接应用ISV、商家系统是否正常运行,应该时刻通过应用管家控制台关注RDS实例的性能状态,针对特定故障结合方案中间介绍的方法和案例,进行优化。

解决方案中心

FAQ

关于此文档暂时还没有FAQ
返回
顶部