今天tanb测试时发现192.168.1.205上MySQL经常CPU很高,占到差不多100%。期间曾多次手动重起服务恢复。
在并非存在大量外部请求的情况下,CPU过高通常是持续时间比较长的任务造成的,甚至只一个未被正确设计的任务。
用SHOW PROCESSLIST命令检查发现正在执行下面的SQL操作.
用KILL命令杀死对应进程后,CPU使用率降下来.
初步判定是此命令引起的.
下面的语句对实际的SQL做了简化(省略了查询字段和占位条件表达式):
SELECT COUNT(*) FROM (SELECT tb_gdsn_tradeitem.ObjectID AS 记录编号,...
FROM tb_gdsn_log,tb_gdsn_newgoods_status,tb_gdsn_tradeitem
WHERE tb_gdsn_log.ObjectID = tb_gdsn_tradeitem.History_ObjectID
AND tb_gdsn_newgoods_status.StatusCode=tb_gdsn_tradeitem.Status
AND tb_gdsn_tradeitem.Status=0
AND tb_gdsn_tradeitem.UpdateTime>='2010-12-1' AND tb_gdsn_tradeitem.UpdateTime<'2012-12-05 23:59:59'
AND tb_gdsn_tradeitem.ReUsed = 0) _T_
在SQLyog中执行此命令并不耗时.
数据规模如下:
SELECT COUNT(*) FROM tb_gdsn_tradeitem; /// 2313
SELECT COUNT(*) FROM tb_gdsn_log; /// 13559
SELECT COUNT(*) FROM tb_gdsn_newgoods_status; /// 7
调整tb_gdsn_tradeitem.UpdateTime范围也未见出现类似情况.
检查各表的索引情况:
.tb_gdsn_log:
---PRIMARY(ObjectID)
.tb_gdsn_tradeitem
---PRIMARY(ObjectID)
---OrgID,GTIN,GLN:UNIQUE
---History_ObjectID:UNIQUE
.tb_gdsn_newgoods_status
---PRIMARY(StatusCode)
状态和标志字段通常不需要建索引,如tb_gdsn_tradeitem.Status,tb_gdsn_tradeitem.ReUsed.
网上有资料表明,某些查询命令会导致MySQL的CPU占用率过高.如缺少索引支持的LEFT JOIN.
最后建议增加tb_gdsn_tradeitem.UpdateTime索引.
上述现象并不能得到令人信服的解释.
继续观察!
处理问题过程中,联想到一些开发中存在的问题,这些问题需要深入人心,需要执行对策。
关于数据库设计
过去,数据库设计是我们设计环节中最被忽略的.承担设计的人是否有下面的考虑呢。
.设计表的依据是什么
.如何比较不同设计的优劣
.表的数据规模如何(什么级别,增长速度)
软件开发的3个要素:产品定义,设计,测试。
一直以来,设计没有被严格要求和控制。
底层数据库设计的不合理,机制上的缺陷造成了大量的后期修复任务。因为这些本应在设计阶段避免的缺陷的存在,导致一系列的逻辑和性能问题。
而且,修复此问题也因结构性问题使得风险和成本高昂。(结构性修改对代码的冲击,回归测试,兼容性考虑,大范围升级,升级时数据处理)
对设计一直也有要求和关注,然而没有有效执行。
而且,在系统分析和数据结构设计方面更是薄弱,我们有把数据库表的设计任务交给没有任何经验的人的经历。
都明白一个道理,构造一个大厦,越下层越重要。
框架和基础应用组件是对这些住在大厦里的人不是明显感觉到的东西,但其价值和重要性毋庸置疑。
如同地面下的桩基,隐藏在墙体内部的各种管线系统。
顺便提一下,示例SQL命令中文字段别名的用法问题。
这种写法不宜使用.也许因为编码规范没有涉及到这方面。
对于这种写法,可以想到的优点是:(1)注释作用(2)直接返回给客户端用于显示标题
缺点呢?(看不习惯不说)
---字符集问题:限定了程序和数据库的字符集
这个缺点是不可回避的.会对以后系统适应性扩展留下大尾巴.
注释有其它替代方式(如良好的代码风格和注释,文档).
至于优点(2),实际上是把表示和数据耦合了,是违反惯例的做法.
一句话,基于设计编码.
补充一句,基于定义设计.
这是开发的全部.(测试是个独立单元)