帝国 CMS 数据库查询优化
照着这篇做完,你能把帝国 CMS 的页面生成时间从两三秒压到一秒以内,并且知道以后慢了该从哪里下手排查。
帝国 CMS 的性能问题九成出在数据库上:信息表(phome_ecms_news 这类)动辄几十万行,栏目页一刷新就是全表扫描。下面按"先测、再改、后验证"的顺序走一遍。
第一步:先找到慢在哪,别瞎改配置
这一步的目标是拿到具体的慢 SQL,而不是凭感觉调参数。最直接的办法是开 MySQL 慢查询日志。
宝塔面板用户:进 软件商店 → MySQL 8.0 → 配置修改,找到 slow_query_log,改成 slow_query_log = On、long_query_time = 1,保存后重载配置,日志在 /www/server/data/mysql-slow.log,跑一天再回来看。
命令行方式:
SET GLOBAL slow_query_log = 1;
SET GLOBAL long_query_time = 1;
拿到可疑 SQL 后,前面加 EXPLAIN 看执行计划,重点看 type 和 rows 两列:
EXPLAIN SELECT id,title,newstime FROM phome_ecms_news WHERE classid=5 ORDER BY newstime DESC LIMIT 10;
type 出现 ALL 就是全表扫描,rows 接近总行数就是没走索引——这就是你要动刀的地方。
注意:帝国 CMS 默认用的是 MyISAM 引擎,慢查询日志里会混入大量后台自己的管理 SQL,别把"后台刷新页面"的慢查询当成前台问题。
第二步:给信息表补组合索引
大部分慢查询来自栏目页列表,条件是"某栏目 + 按时间倒序",这正好是一个组合索引能解决的。先看现有索引,避免重复添加:
SHOW INDEX FROM phome_ecms_news;
帝国 CMS 默认只给了 classid 和 newstime 两个单列索引,MySQL 只能二选一。补一个组合索引:
ALTER TABLE phome_ecms_news ADD INDEX idx_class_newstime (classid, newstime);
加完再用第一步的 EXPLAIN 跑一遍,rows 应该从几万掉到几十。
注意:几十万行以上的 MyISAM 表执行
ALTER TABLE会锁表,务必在凌晨低峰做;条件允许先把表转成 InnoDB(ALTER TABLE phome_ecms_news ENGINE=InnoDB;),之后再加索引可以带ALGORITHM=INPLACE, LOCK=NONE,不阻塞读写。
第三步:用副表把大字段拆出去
帝国 CMS 的信息表把正文 newstext 和标题、时间放在同一张表里,而正文是 TEXT 大字段。列表页只需要标题和时间,却被迫读整行,I/O 白白浪费。帝国 CMS 自带副表机制专治这个。
进后台 系统 → 数据表管理 → 管理数据表,找到你的信息表(如"新闻系统数据表 phome_ecms_news"),点右侧"修改",在表设置里找到副表数量,填 3 到 5,提交。系统会把正文按 id % 副表数 拆到 phome_ecms_news_data_1、_2…… 之后列表查询只碰主表,速度立竿见影。
注意:拆副表会重建数据,操作前先用 系统 → 数据表管理 → 备份数据表 全量备份一次,别省这一步。
第四步:清垃圾、整理碎片
MyISAM 表频繁增删后会产生空洞,OPTIMIZE TABLE 可以回收空间并重建索引:
OPTIMIZE TABLE phome_ecms_news;
顺手清理两类垃圾:后台 信息管理 → 回收站 里彻底清空已删信息;phome_enewslog、phome_enewsloginfail 这类日志表可以直接 TRUNCATE,它们对前台毫无用处。
第五步:减少动态查询——缓存和静态化
数据库改完,还要让查询次数降下来。帝国 CMS 本身是静态化 CMS,别让它跑动态。
后台 系统 → 系统设置 → 系统参数设置,切到性能相关标签页,把信息页、列表页的缓存时间设成 3600 秒以上;再到 系统 → 数据更新中心,依次执行"刷新所有信息内容页面""刷新所有列表页面""刷新首页",让前台直接读 HTML。
模板里的灵动标签 [e:loop] 一定要写 row='10',不写条数上限的标签会拖垮整页。
第六步:调 MySQL 服务端参数
如果表已经转成 InnoDB,在 软件商店 → MySQL → 配置修改 里调整:
innodb_buffer_pool_size:设为服务器物理内存的 50%~70%tmp_table_size和max_heap_table_size:都设 64M,减少磁盘临时表- 仍是 MyISAM 的表,重点调
key_buffer_size,设 256M 左右
改完保存并重启 MySQL。
注意:
innodb_buffer_pool_size一次别调太高,要和 PHP-FPM、Nginx 抢内存,先看服务器剩余可用内存再定。
小结
- 先开慢查询日志 +
EXPLAIN定位,再动手改,别凭感觉调参数 - 给信息表补
(classid, newstime)组合索引,是收益最大的一步 - 用帝国自带副表机制把
newstext拆走,列表页只读主表 OPTIMIZE TABLE整理碎片,清空回收站和无用日志表- 后台开启页面缓存 + 刷新静态页,把动态查询变成读 HTML
- MySQL 参数只调
innodb_buffer_pool_size、key_buffer_size这几个关键的
原文链接:https://www.gj0.com/thread-988.html
转载请注明出处并保留本声明;内容仅代表作者观点,与本站立场无关。若本文涉嫌侵权,请联系本站处理。