帝国 CMS 大列表分页慢
照着做完,你能把帝国 CMS 大列表分页从「点一下等十几秒」压到一秒内出结果,并且知道每一步为什么有效。
第一步:先确认慢在数据库还是慢在生成
打开要排查的列表页第 2 页,按 F12 切到「网络」面板刷新,看 time_starttransfer(首字节时间)。如果第 1 页很快、第 5 页开始变慢,基本可以断定是分页的 COUNT(*) 统计语句在拖。后台进入「系统 → 系统设置 → 系统参数设置 → 其他设置」,把「是否记录 SQL 查询」或「SQL 查询记录」相关项打开,再访问一次动态列表页(地址形如 /e/action/ListInfo/?classid=1&page=5),到「系统 → 执行 SQL」或日志里看实际执行语句和耗时,先把慢语句抓出来再动手。
第二步:把列表页改成静态生成(收益最大)
这一步做完,前台的列表分页不再查数据库,直接读 HTML 文件。
后台进「栏目 → 管理栏目」,找到栏目点「修改」,切到「生成选项」标签页:把「生成栏目页 HTML」选为「是」,「生成内容页 HTML」按需,「列表页每页显示条数」按设计填写。再切到「模板选项」,给「列表页模板」指定好模板。保存后进「系统 → 数据更新中心 → 刷新栏目页」,勾选该栏目点「开始刷新」,生成的静态文件就是 list_1.html、list_2.html……以后新增内容只要重新生成栏目页即可。
注意:帝国 CMS 的静态列表分页不会自动跟内容同步,发布文章后要重新生成栏目页,建议在「系统 → 计划任务」里建定时生成,别手工点。
第三步:给主表补上复合索引
这一步是给没做静态化、只能用动态分页的场景兜底。帝国 CMS 文章列表默认是「checked=1 + classid + 按 newstime 倒序」,单列索引往往不够,需要复合索引。先看表前缀,打开 e/config/config.php 找 $ecms_config['db']['dbtbpre'],默认是 phome_。
EXPLAIN SELECT id FROM phome_ecms_news
WHERE checked=1 AND classid IN (1,2) ORDER BY newstime DESC LIMIT 0,20;
如果 Extra 里出现 Using filesort,加索引:
ALTER TABLE phome_ecms_news ADD INDEX idx_list (classid, checked, newstime);
注意:大表加索引会锁表,建议在低峰期做,并且先用
mysqldump备份该表。
第四步:限制分页的总数统计开销
帝国 CMS 分页要算总页数,就必须对大表跑一次 COUNT(*),数据量上百万时这一句比取数据本身还慢。打开 e/class/connect.php,搜索 function page1 和 function PageInfo,这两个是分页相关函数,找到里面统计总数的 COUNT(*) 查询,把它改成带上限的子查询:
SELECT COUNT(*) FROM (
SELECT 1 FROM phome_ecms_news
WHERE checked=1 AND classid IN (1,2)
LIMIT 100000
) AS t;
这样最多只扫 10 万行,超过部分页数显示到上限为止,用户根本翻不到那么深。改完记得用超级管理员账号进「系统 → 数据更新中心 → 更新缓存」清一次缓存。
注意:直接改核心文件,帝国 CMS 升级时会被覆盖,改前把原文件另存一份
connect.php.bak。
第五步:清掉模板里的循环查询
进「模板 → 模板管理」,找到该栏目的列表模板点「修改」。列表循环体 [!--empirenews.listtemp--] 到 [!--empirenews.listtemp--] 之间,如果写了 [e:loop]、[ecmsinfo] 这类万能标签,每条记录都会再查一次库,20 条就是 20 次查询。把这些标签移到循环外,用一条 [e:loop] 一次取多条;循环内只输出 [!--title--]、[!--titleurl--]、[!--newstime--] 这类字段变量。改完点「保存模板」,再「更新缓存」。
第六步:用命令行验证效果
curl -o /dev/null -s -w "%{time_starttransfer}\n" "https://你的域名/list_1.html"
curl -o /dev/null -s -w "%{time_starttransfer}\n" "https://你的域名/e/action/ListInfo/?classid=1&page=5"
对比两条命令的返回值,静态页应该在 0.1 秒以内,动态页优化后也应落到 1 秒以内。如果动态页还是慢,回到第一步看慢日志,确认新索引是否真的被用上。
小结
- 优先静态化:栏目「生成选项」开启生成栏目页 HTML,再用数据更新中心刷新。
- 动态分页的瓶颈通常是
COUNT(*),用LIMIT子查询截断统计上限。 - 主表按
classid + checked + newstime建复合索引,用EXPLAIN确认没有Using filesort。 - 列表模板循环体里禁止放查询型万能标签。
- 改核心文件前备份,改完清缓存,用
curl的time_starttransfer做前后对比。
原文链接:https://www.gj0.com/thread-978.html
转载请注明出处并保留本声明;内容仅代表作者观点,与本站立场无关。若本文涉嫌侵权,请联系本站处理。