杰奇CMS数据库备份失败多因章节表过大、锁表超时或空间不足,与网站访问慢同源,本文从备份命令、索引优化、分表缓存、模板改造到移动端适配,提供全站性能优化方案,解决故障并提升加载速度。
杰奇CMS数据库备份失败,通常不是 mysqldump 命令写错,而是章节表 jieqi_article_chapter 过大、MyISAM 锁表超时、/tmp 空间不足或表已经损坏,这个故障与网站访问速度慢、阅读页加载卡顿同源:数据表膨胀、索引缺失、模板直查数据库、没有缓存,下面直接给命令、SQL 和模板修改方法,不再铺垫。
杰奇CMS数据库备份失败与性能优化实战,分表、缓存、模板、移动端全方案
杰奇CMS数据库备份失败的快速修复
先确认失败类型,执行备份时如果遇到:
Got error 28 from storage engine:服务器磁盘或/tmp空间不足。Lock wait timeout exceeded:备份对 MyISAM 表加了全局锁,章节表太大导致超时。Table is marked as crashed:表损坏,需要先修复再备份。
检查磁盘:
df -h du -sh /tmp /var/lib/mysql
修复损坏表:
mysqlcheck -u root -p --auto-repair --check jieqi_db
杰奇CMS如果还在用 MyISAM,建议先把核心表转 InnoDB,备份和并发性能都会好很多:
ALTER TABLE jieqi_article_article ENGINE=InnoDB; ALTER TABLE jieqi_article_chapter ENGINE=InnoDB;
InnoDB 下使用单事务备份,不再锁全表:
mysqldump -u root -p \ --single-transaction \ --quick \ --max_allowed_packet=1G \ --skip-lock-tables \ jieqi_db > /backup/jieqi_$(date +%F).sql
如果章节表已经非常大,不要一次导出,先单独导出表结构,再按 articleid 区间分批导出章节内容:
mysqldump -u root -p --no-data jieqi_db > jieqi_schema.sql mysqldump -u root -p \ --single-transaction --quick \ --where="articleid BETWEEN 1 AND 50000" \ jieqi_db jieqi_article_chapter > chapter_1_50000.sql
每次备份完检查 SQL 文件末尾是否包含 -- Dump completed,没有就是中断了。
网站访问速度慢怎么优化
杰奇CMS首页、列表页慢,通常是查询没有走索引,或者每次访问都实时读取最新更新、推荐位、排行,先补齐核心索引:
ALTER TABLE jieqi_article_article ADD INDEX idx_lastupdate (lastupdate), ADD INDEX idx_allvisit (allvisit), ADD INDEX idx_articleid (articleid); ALTER TABLE jieqi_article_chapter ADD INDEX idx_article_chapter (articleid, chapterid), ADD INDEX idx_article_order (articleid, chapterorder);
开启慢查询日志定位具体 SQL:
SET GLOBAL slow_query_log = ON; SET GLOBAL long_query_time = 1; SET GLOBAL log_queries_not_using_indexes = ON;
然后到 MySQL 数据目录查看慢日志,杰奇站点大量慢查询集中在:
SELECT * FROM jieqi_article_chapter WHERE articleid = xxx ORDER BY chapterorder DESC LIMIT 10;
这种查询必须走 idx_article_order 索引。SELECT * 会拖动 TEXT 类型的章节内容字段,列表页只需要章节名和章节ID:
SELECT chapterid, chaptername, chapterorder FROM jieqi_article_chapter WHERE articleid = xxx ORDER BY chapterorder DESC LIMIT 10;
首页和列表页建议用 Nginx FastCGI Cache 缓存 30 到 60 秒,杰奇小说站游客访问占比高,短时间全页缓存能显著降低 PHP 和 MySQL 压力:
fastcgi_cache_path /var/run/jieqi_cache levels=1:2 keys_zone=JIEQI:64m inactive=1h max_size=512m;
server {
set $skip_cache 0;
if ($request_method = POST) { set $skip_cache 1; }
if ($http_cookie ~* "jieqi_user") { set $skip_cache 1; }
location ~ \.php$ {
fastcgi_cache JIEQI;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
fastcgi_cache_valid 200 40s;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
include fastcgi_params;
fastcgi_pass 127.0.0.1:9000;
}
}
章节表过大怎么分表处理
杰奇CMS的 jieqi_article_chapter 一张表很容易跑到几百万甚至上千万行,直接拆成多张物理表需要改核心读写逻辑,风险高,不建议线上直接做,更稳妥的做法是“归档 + 分区”。
先把完结老书归档到独立表:
CREATE TABLE jieqi_article_chapter_archive LIKE jieqi_article_chapter;
INSERT INTO jieqi_article_chapter_archive
SELECT c.*
FROM jieqi_article_chapter c
JOIN jieqi_article_article a ON c.articleid = a.articleid
WHERE a.isfull = 1
AND a.lastupdate < UNIX_TIMESTAMP('2023-01-01');
DELETE c
FROM jieqi_article_chapter c
JOIN jieqi_article_article a ON c.articleid = a.articleid
WHERE a.isfull = 1
AND a.lastupdate < UNIX_TIMESTAMP('2023-01-01')
LIMIT 10000;
注意 DELETE ... LIMIT 要反复执行,避免长事务锁表。
当前表如果已经转成 InnoDB,可以直接做 KEY 分区,把一张大表拆成多个物理分区:
ALTER TABLE jieqi_article_chapter PARTITION BY KEY(chapterid) PARTITIONS 16;
这样磁盘上会拆成 16 个分区文件,写入、索引维护和备份压力都会下降,不要按 articleid 做 HASH 分区,如果主键是 chapterid,分区键不包含主键会报错,KEY 分区更省事。
阅读页加载卡顿怎么改善
阅读页最卡的是章节正文读取和上一章、下一章查询,不要每次打开阅读页都实时读 TEXT 大字段,先给章节内容做文件缓存:
$articleid = intval($_GET['articleid']);
$chapterid = intval($_GET['chapterid']);
$cacheFile = "/var/www/cache/chapter/{$articleid}/{$chapterid}.html";
if (file_exists($cacheFile) && time() - filemtime($cacheFile) < 3600) {
readfile($cacheFile);
exit;
}
ob_start();
// 这里查数据库并渲染章节页
$chapter = $db->query("
SELECT chapterid, chaptername, chaptercontent
FROM jieqi_article_chapter
WHERE articleid = {$articleid}
AND chapterid = {$chapterid}
LIMIT 1
");
echo renderChapter($chapter);
file_put_contents($cacheFile, ob_get_contents());
ob_end_flush();
上一章、下一章建议直接按 chapterorder 计算,不要再做排序子查询:
SELECT chapterid, chaptername, chapterorder FROM jieqi_article_chapter WHERE articleid = ? AND chapterorder < ? ORDER BY chapterorder DESC LIMIT 1;
如果章节表已经做了分区,这类查询会更快,阅读页还可以用 Ajax 加载下一章,减少整页输出。
模板标签调用和修改方法
杰奇CMS模板目录一般在:
/themes/你的模板名/
列表页通常是 list.html,阅读页是 read.html,模板里常见循环标签:
{?section name=i loop=$articlerows?}
<a href="{?$articlerows[i].url?}">{?$articlerows[i].articlename?}</a>
{?/section?}
性能问题往往出在循环里再次查库,比如首页最新更新、推荐位、排行,不要在模板层反复调用带条件的标签,推荐在模块或入口 PHP 里查一次,然后写静态 HTML 片段,模板只负责 include:
// 首页最新更新,每5分钟生成一次
$cacheFile = '/var/www/cache/index_lastupdate.html';
if (!file_exists($cacheFile) || time() - filemtime($cacheFile) > 300) {
$rows = $db->query("
SELECT articleid, articlename, lastupdate
FROM jieqi_article_article
ORDER BY lastupdate DESC
LIMIT 20
");
$html = buildLastupdateHtml($rows);
file_put_contents($cacheFile, $html);
}
$tpl->assign('lastupdate_html', file_get_contents($cacheFile));
然后在模板里直接调用:
<div class="lastupdate">
{?$lastupdate_html?}
</div>
阅读页模板里的章节正文输出,不要做二次处理,直接输出缓存字段,需要修改标签时,优先把复杂标签改成模块级缓存,而不是在 section 循环里加多个 if 判断。
移动端适配怎么处理
不要直接在 PC 模板上叠加响应式,尤其杰奇CMS旧模板大多是表格布局,强改 CSS 很容易乱,建议单独做一套移动端模板,放在:
/themes/mobile/
在入口 PHP 按 UA 切换模板:
$ua = $_SERVER['HTTP_USER_AGENT'] ?? '';
if (preg_match('/(android|iphone|ipad|mobile|webos)/i', $ua)) {
define('JIEQI_THEME_NAME', 'mobile');
} else {
define('JIEQI_THEME_NAME', 'default');
}
移动端 read.html 必须加 viewport:
<meta name="viewport" content="width=device-width, initial-scale=1.0">
移动端模板只保留核心内容:书名、章节名、正文、上一章、下一章,移除浮动广告、侧边栏和大量推荐位。
图片列表可以懒加载:
<img src="" data-src="{?$articlerows[i].cover?}" loading="lazy" alt="">
移动端不需要每页查询 20 条列表,控制在 10 条以内,能明显降低 DB 压力。
缓存配置怎么设置
杰奇CMS建议按层级设置缓存,不要只依赖系统自带的文件缓存。
PHP OPcache
opcache.enable=1 opcache.memory_consumption=256 opcache.max_accelerated_files=10000 opcache.revalidate_freq=60 opcache.validate_timestamps=1
保存后重启 PHP-FPM 或 Apache。
页面级缓存
小说站游客为主,可以对首页、列表页、阅读页做 Nginx FastCGI Cache,首页缓存 30 到 60 秒,列表页 60 秒,阅读页如果做了章节内容静态化,也可以缓存 10 分钟以上。
Redis 缓存高频查询
杰奇CMS如果查询缓存没有内置 Redis,可以在模块层接入:
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$redis->auth('your_password');
$key = 'jieqi_article_' . $articleid;
$data = $redis->get($key);
if (!$data) {
$data = $db->getOne("SELECT ... FROM jieqi_article_article WHERE articleid = {$articleid}");
$redis->setex($key, 600, json_encode($data));
}
不要把 Redis 当成完整依赖,至少要保留文件缓存兜底,防止 Redis 挂了直接打崩 MySQL。
数据库定期维护清理建议
杰奇CMS长期运行后会有大量重复章节、无效采集数据和碎片,建议设置每周维护脚本。
每周索引和表保养
0 3 * * 0 mysqlcheck -u root -p'你的密码' \ --optimize --tables jieqi_article_chapter jieqi_article_article \ > /dev/null 2>&1
清理重复章节
DELETE c1 FROM jieqi_article_chapter c1 JOIN jieqi_article_chapter c2 ON c1.articleid = c2.articleid AND c1.chapterorder = c2.chapterorder AND c1.chapterid > c2.chapterid;
定期归档完结老书
每季度执行一次第三节的归档 SQL,让读写都集中在热数据上。
备份策略
- 每周一次全量备份。
- 每天一次差异备份或至少备份最近 7 天的 binlog。
- 备份目录不要放在 Web 根目录下。
0 2 * * 0 mysqldump -u root -p'你的密码' \ --single-transaction --quick --max_allowed_packet=1G \ jieqi_db | gzip > /backup/jieqi_full_$(date +%F).sql.gz
监控表状态
CHECK TABLE jieqi_article_chapter; SHOW TABLE STATUS LIKE 'jieqi_article_chapter';
重点关注 Data_free 和表大小变化。Data_free 长期较大,说明碎片多,需要执行 OPTIMIZE TABLE。
杰奇CMS数据库备份失败只是一个信号,背后通常是章节表过大、索引缺失、缓存不到位,把备份、分表、模板改造、移动端和缓存一起处理,才能把站点从“能打开”拉回到“打开快”。


