2007年3月我发现 discuz 论坛的数据库结构设计有一些疏忽,有许多查询子句的条件比较,都没有建立 Index 索引。当时我所检查的那个数据表,记录只有几千条,因此对 CPU 负荷不大。现在这个数据库表,上千万的记录检索,可以想象,如果数据表结构设计不规范,没有提供索引,所耗费的时间是一个恐怖的数字。有关 MySQL 建立索引的重要性,可以参见我的这篇文章底部的说明
为了调试方便,我从 dizcus 的官网下载了其最新的 Dizcus! 5.5.0 论坛程序.
我首先检查了 my.ini 的参数配置,一切正常。进入 MySQL 的命令行,调用 show processlist 语句,查找负荷最重的 SQL 语句,结合 Discuz 论坛的源码,发现有以下语句导致 CPU 上升:
复制代码 代码如下:
mysql> show processlist; +-----+------+----------------+---------+---------+------+------------+--------- -----------------------------------------------------------------+ | Id | User | Host | db | Command | Time | State | Info
+-----+------+----------------+---------+---------+------+------------+--------- -----------------------------------------------------------------+ | 363 | root | localhost:1393 | history | Query | 0 | statistics | SELECT C OUNT(*) FROM cdb_pms WHERE msgfromid=11212 AND folder='outbox' | +-----+------+----------------+---------+---------+------+------------+---------
检查 cdb_pms 表的结构:
复制代码 代码如下:
mysql> show columns from cdb_pms; +-----------+------------------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-----------+------------------------+------+-----+---------+----------------+ | pmid | int(10) unsigned | NO | PRI | NULL | auto_increment | | msgfrom | varchar(15) | NO | | | | | msgfromid | mediumint(8) unsigned | NO | MUL | 0 | | | msgtoid | mediumint(8) unsigned | NO | MUL | 0 | | | folder | enum('inbox','outbox') | NO | | inbox | | | new | tinyint(1) | NO | | 0 | | | subject | varchar(75) | NO | | | | | dateline | int(10) unsigned | NO | | 0 | | | message | text | NO | | | | | delstatus | tinyint(1) unsigned | NO | | 0 | | +-----------+------------------------+------+-----+---------+----------------+ 10 rows in set (0.00 sec)