织梦批量删除未审核文章完整SQL实战指南:47步+10维度避坑
织梦后台堆满未审核垃圾文章和评论怎么办?两条DELETE SQL搞定批量清理,覆盖dede_archives主表与addonarticle/arctiny关联清理、五项必做备份准备、版本差异、真实事故复盘与百万级数据分批删除性能调优。
本文目录
- 为什么不能直接在后台一条条删
- 织梦的数据表结构:理解了再动手
- 主表 dede_archives
- 副表 dede_addonarticle(普通文章正文)
- 微数据表 dede_arctiny
- 评论表 dede_feedback
- 其他特殊频道的副表
- 操作前必须完成的五项准备
- 全库备份
- 单表导出
- 用SELECT先确认要删多少
- 抽样查10条记录人工肉眼审
- 关闭前台访问入口(可选但推荐)
- 核心SQL:两条命令搞定批量清理
- 批量删除未审核文档
- 批量删除未审核评论
- 评论关联数据清理
- 重建文档计数与缓存
- 进阶清理:把垃圾源头一并断掉
- 关闭未登录用户评论
- 添加敏感词与正则过滤
- 加图形验证码或行为验证
- 限频与IP黑名单
- 真实事故复盘:一次少加WHERE的代价
- 不同织梦版本的差异
- 织梦5.6/5.7
- 织梦5.8/dede biz
- 织梦M版/手机版独立分表
- 国产二开版本
- 清理之后的健康检查清单
- 性能调优:百万级清理怎么做
- 分批删除
- 表碎片整理
- 索引重建
- 静态HTML文件残留处理
- 物理删除
- robots与404
- 常见问题解答
- 删完之后文档ID还能复用吗?
- 执行DELETE时报Lock wait timeout exceeded怎么办?
- 能不能用一条SQL同时删主表和附属表?
- 删了正常评论怎么办?
- 清理后栏目页文档数还是旧的怎么办?
- SQL命令行工具找不到怎么办?
- 清理后搜索引擎一直来抓已删文章怎么办?
- 批量清理对SEO有负面影响吗?
- 写在最后
保哥维护过的几十个DedeCMS站点,几乎每一个都会在某个阶段遇到同一种灾难——评论审核队列里堆了几万条垃圾评论,未审核的草稿文章塞了半个数据库。后台一条条点删除,先不说效率,浏览器卡得连页面都打不开;用插件清理又怕动到正常数据;让运维直接 drop 表又怕牵连主站。织梦的特殊在于它的“一文多表”架构——一篇文章的数据分散在 dede_archives、dede_addonarticle、dede_arctiny 三张表里,删一篇文章如果只删主表,剩下两张表里的孤儿数据会让后台报错、前台 500,一年后想恢复连关联都找不回来。
这篇文章保哥把当年沉淀下来的批量清理方案完整写出来,包含两条核心SQL、五项必做的事前准备、织梦三张关联表的清理顺序、不同织梦版本的差异、一个真实事故复盘、以及清理之后必须跟进的健康检查清单。如果你正在或即将面对一个堆满垃圾内容的织梦后台,可以严格按本文流程操作,并且能从中读到很多保哥过去十几个客户站翻车后才学到的细节。
为什么不能直接在后台一条条删
织梦后台的评论管理列表分页通常每页20或30条,5万条垃圾评论意味着至少1700次翻页加勾选加提交,每次提交的POST请求会触发以下操作。
- 写一次dede_log操作日志,单条日志大概100字节,5万条要新增近5MB日志。
- 重建一次评论缓存,data/cache下面的pl_*.inc会被重写。
- 触发一次主题模板的钩子(如果你装了某些插件),相当于额外执行一段PHP。
- 写一次会话状态到session,记录最后操作时间。
这意味着删除速度被限制在每分钟几百条左右,删完整个队列需要几个小时,期间MySQL还会因为大量小事务而IO被打满。保哥2018年就经历过一次:客户的虚拟主机被空间商误判为攻击源,强制重启了MySQL,后台清理工作直接中断,已经删了三千条但织梦的arcrank标记并没有持久化完整,重新登录后看到的依然是原来的5万条,等于白干。
相比之下,直接在SQL命令行工具里跑一条DELETE语句,5万条数据通常200毫秒内完成,且只产生一次事务。这就是为什么保哥推荐SQL方案。一次事务也意味着要么全部成功、要么全部回滚,不会出现“删一半中断”这种最难处理的中间状态。
织梦的数据表结构:理解了再动手
很多新手以为“一篇文章对应一行数据”,对织梦来说大错特错。织梦从5.3版本开始引入“主辅分表”架构,一篇文章的数据是这样分布的。
主表 dede_archives
每篇文章在这张表里有一行,存放最重要的元数据:id、typeid(栏目)、title、shorttitle、color、writer、source、litpic(缩略图)、pubdate、senddate、arcrank、click、ismake、channel等字段。前台分页查询、栏目页生成都是查这张表。arcrank的含义:-1表示未审核,0表示已审核(开放浏览),其他正整数表示需要付费或会员等级才能查看。
副表 dede_addonarticle(普通文章正文)
这张表里只有aid、typeid、body、redirecturl、templet、userip这几个字段。body就是文章正文HTML。dede_archives和dede_addonarticle通过id和aid一一对应。如果你只删主表不删副表,副表里会出现aid指向已删主表的孤儿数据,长此以往数据库膨胀。
微数据表 dede_arctiny
这是织梦自己维护的一个“轻量索引表”,存所有内容的id、typeid、channel、senddate、sortrank、mid,用于快速做关联查询。织梦的文档列表筛选、Tag关联检索都靠它。这张表的孤儿数据会让后台“文档列表”里出现一行行空白记录,点进去500。
评论表 dede_feedback
评论的所有字段都在这一张表里:aid(关联文章)、typeid、username、ip、ischeck、dtime、mid、msg。ischeck=0是未审核,ischeck=1是已审核。和文章不同,评论没有副表,所以清理评论比清理文章简单很多。
其他特殊频道的副表
如果你的站点装了图集、软件、商品、专题等额外频道,每个频道都有自己的副表:图集是dede_addonimages,软件是dede_addonsoft,商品是dede_addonshop。清理时这些表都要一并处理,否则同样产生孤儿数据。
操作前必须完成的五项准备
直接执行DELETE的风险不在SQL本身,而在于一旦删错没法恢复。保哥给所有客户的清理流程,第一步永远是这五件事,少做一件都不行。
全库备份
mysqldump -u root -p --single-transaction --routines --triggers \
your_dede_db > /backup/dede_$(date +%Y%m%d_%H%M).sql--single-transaction保证备份过程中不锁表,对在线站点很重要。备份文件至少留三份,本地一份、对象存储一份、邮箱发自己一份。备份完后用du -sh看一下大小,再用head -50看一下文件开头的“Dumping data for table”能不能正常出现,确保备份没有中途断掉。
单表导出
如果整库太大,至少把dede_archives、dede_addonarticle、dede_arctiny和dede_feedback四张表单独导一次:
mysqldump -u root -p your_dede_db dede_archives dede_addonarticle dede_arctiny dede_feedback > /backup/four_tables.sql这份单表备份能让你在出问题时快速回滚单张表,比整库恢复快十倍以上。
用SELECT先确认要删多少
SELECT COUNT(*) FROM `dede_archives` WHERE arcrank = -1;
SELECT COUNT(*) FROM `dede_feedback` WHERE ischeck = 0;如果第一条返回了几十万,先别急着删。可能是有人误把所有正常文章批量改成了未审核状态。保哥真的遇到过:客户实习生在后台批量操作时勾错了选项,把12万篇正常文章打成arcrank=-1,要是直接DELETE了,整个站就空了。
抽样查10条记录人工肉眼审
SELECT id, title, pubdate, arcrank FROM `dede_archives`
WHERE arcrank = -1 ORDER BY id DESC LIMIT 10;看一下抽样里的title是不是都长得像垃圾内容(乱码、外链广告、博彩词)。如果出现正常的标题,立刻停止,回到3.3重新评估。也要倒着看一遍ORDER BY id ASC LIMIT 10,因为有些客户的“未审核”堆积是几年前的存货,新增的可能反而是正常的还没审完。
关闭前台访问入口(可选但推荐)
如果你的清理量很大(百万级),删除期间可能产生表锁。先在.htaccess里加一段维护页,只放行你自己的IP,其他用户看到维护页。或者直接在Nginx里 return 503,让搜索引擎蜘蛛看到“Service Unavailable”状态码主动延迟下次抓取,避免清理过程中蜘蛛拿到不完整数据。
核心SQL:两条命令搞定批量清理
做完上面五件事后,进入织梦后台、系统、SQL命令行工具,分两次执行下面两条SQL。不要复制带反引号的版本到部分国产建站环境,有些MySQL 5.5老版本对反引号兼容差,保哥下面给的是最稳的版本。
批量删除未审核文档
DELETE FROM `dede_archives` WHERE arcrank = -1;执行后,织梦的主表dede_archives里所有arcrank为-1的记录都会被清空。但织梦的文档数据是分表的——还有dede_addonarticle、dede_arctiny等附属表里的数据。完整清理需要再补两条:
DELETE FROM `dede_addonarticle` WHERE aid NOT IN (SELECT id FROM `dede_archives`);
DELETE FROM `dede_arctiny` WHERE id NOT IN (SELECT id FROM `dede_archives`);这两条会把附属表里失去主表关联的孤儿数据也删掉。如果你的站点有图集、软件、商品等额外频道,要把对应副表也清一遍:
DELETE FROM `dede_addonimages` WHERE aid NOT IN (SELECT id FROM `dede_archives`);
DELETE FROM `dede_addonsoft` WHERE aid NOT IN (SELECT id FROM `dede_archives`);
DELETE FROM `dede_addonshop` WHERE aid NOT IN (SELECT id FROM `dede_archives`);批量删除未审核评论
DELETE FROM `dede_feedback` WHERE ischeck = 0;ischeck = 0表示未通过审核。如果你想保留某些已审核但被错误标记成0的评论,可以加上时间范围:
DELETE FROM `dede_feedback`
WHERE ischeck = 0 AND dtime < UNIX_TIMESTAMP('2024-01-01');这样只清理2024年之前的未审核评论。dtime字段是Unix时间戳格式,UNIX_TIMESTAMP函数把字符串日期转成时间戳。
评论关联数据清理
织梦的评论数本身保存在dede_archives.feedback字段(每篇文章的评论数)。删完评论后这个数字会变“假”,前台“评论数N”显示和实际查到的评论数不一致。修正用这条SQL:
UPDATE `dede_archives` a
SET a.feedback = (SELECT COUNT(*) FROM `dede_feedback` f WHERE f.aid = a.id AND f.ischeck = 1);跑完之后每篇文章的评论数就回到真实值。
重建文档计数与缓存
清理完后,到织梦后台、系统、数据库内容修复、一键修复,让织梦重新统计每个栏目下的文档数量。然后到系统、更新缓存,刷一次站点缓存。这两步不做的话,前台栏目页可能会出现“显示100条文档但实际只有30条”的错位。也可以直接跑SQL让dede_arctype的totalarticle字段重新统计:
UPDATE `dede_arctype` t
SET t.totalarticle = (SELECT COUNT(*) FROM `dede_archives` a WHERE a.typeid = t.id AND a.arcrank >= 0);进阶清理:把垃圾源头一并断掉
光删数据不够,垃圾评论会持续涌入。保哥的标准方案是删完之后立刻部署三道防线。
关闭未登录用户评论
后台、模块、评论管理、评论权限设置,把“游客评论”关闭,只允许会员评论。这一刀下去能砍掉80%的垃圾。绝大多数自动化垃圾评论机器人不会模拟完整的注册流程,只会硬怼提交接口。
添加敏感词与正则过滤
在/data/admin/forbidword.txt里加上常见博彩、私彩、五金外链域名。织梦自带的过滤词文件支持每行一个关键词,匹配到就拒绝评论提交。可以粗暴一点直接禁所有带http://的评论,因为正常用户极少会在评论里贴外链。保哥的客户站这条规则上线第一周拦了2.3万条提交,前台体验完全没受影响。
加图形验证码或行为验证
织梦默认验证码弱到几乎可以被OCR直接识别。保哥推荐换成Google reCAPTCHA v3或者腾讯云的天御验证码,集成代码网上很多。reCAPTCHA v3完全无感,根据用户行为评分自动放行或拦截,体验最好。
限频与IP黑名单
在Nginx层加一段限频规则:
limit_req_zone $binary_remote_addr zone=plzone:10m rate=2r/m;
location ~ ^/plus/feedback\.php {
limit_req zone=plzone burst=3 nodelay;
fastcgi_pass 127.0.0.1:9000;
}同一个IP每分钟最多提交2次评论,超出直接返回429。再配合fail2ban定期扫描访问日志,把频繁触发429的IP直接ban进iptables,长效防护。
真实事故复盘:一次少加WHERE的代价
2019年保哥帮一个本地媒体站做清理,操作员当时复制了下面这条SQL:
DELETE FROM `dede_archives`;你看出来问题了吗——少了WHERE arcrank = -1。这条SQL一旦执行,整个dede_archives表会被清空,等于网站所有文章瞬间消失。所幸保哥前一天刚做完全库备份,并且binlog是开着的。整个恢复流程是这样:
- 立刻STOP SLAVE(如果有从库),防止删除被复制过去;
- 用mysqlbinlog --start-datetime=... --stop-datetime=...截取事故前的位置;
- 把昨晚的mysqldump备份恢复到一个临时库;
- 从临时库把dede_archives拷回生产;
- 用binlog重放事故备份点之后到DELETE之前的所有操作。
整个过程花了6个小时,前台用503维护页顶着。事后保哥定了一条规矩:所有DELETE语句必须先以SELECT形式跑一次,确认行数,再改成DELETE提交。流程如下:
-- 第一步:先这样跑
SELECT COUNT(*) FROM `dede_archives` WHERE arcrank = -1;
-- 第二步:确认数字合理后,再这样跑
DELETE FROM `dede_archives` WHERE arcrank = -1;从那次之后保哥再没出过事故。这种“先SELECT再DELETE”的双重确认在所有数据库高危操作里都该默认采用,包括UPDATE批量改字段、TRUNCATE清表。
不同织梦版本的差异
织梦自从被收购后官方维护停滞,社区分化出多个分支版本,清理SQL在不同版本下可能有细节差异。
织梦5.6/5.7
这是市面上最常见的版本,表结构稳定,本文所有SQL都直接适用。注意5.7修补了几个已知的SQL注入漏洞但没改表结构,所以清理逻辑不变。
织梦5.8/dede biz
商业版增加了dede_archives_extend表用于存放扩展字段,清理时要补一条:
DELETE FROM `dede_archives_extend` WHERE aid NOT IN (SELECT id FROM `dede_archives`);织梦M版/手机版独立分表
如果你的织梦装了手机版插件且采用了分表方案,dede_archives_m是手机版主表。要把M版同步清理,否则手机端继续显示已删的垃圾文章。
国产二开版本
市面上常见的“织梦内核XX建站系统”一般会改前缀(比如dede_改成xx_),但表名后缀和字段含义大多保留。清理前用SHOW TABLES LIKE '%archives%'确认表名再动手。
清理之后的健康检查清单
清理完成不代表事情结束,下面这些检查项是保哥从无数次翻车里总结出来的标准动作,每一项都别省。
- 前台所有栏目首页随机刷5个,看有没有500报错或者“无数据”空页。
- 后台“文档列表”翻到最后一页,确认分页正常,每页都有数据。
- 用mysqlcheck -u root -p --auto-repair --optimize your_dede_db跑一次表优化,回收DELETE留下的碎片空间。
- 检查data/cache目录大小,如果还大于50MB手动清空一次。
- 用site:yourdomain.com在百度搜一下,看搜索结果有没有大量已删除文章的快照(如果有,去站长平台提交死链)。
- 检查 /data/sitemap.xml 是否需要重新生成,把已删文章从sitemap里剔掉。
- 看Nginx access日志最近一小时有没有突然增加的404,那就是搜索引擎或外部链接还在访问已删文章。
- 检查RSS输出,确保已删文章不再出现在/data/rss/或/feed路径。
性能调优:百万级清理怎么做
如果你的未审核内容已经堆到百万级,一次DELETE可能跑几个小时甚至几十个小时。这种情况要分批处理,避免锁表过久。
分批删除
DELETE FROM `dede_feedback` WHERE ischeck = 0 LIMIT 5000;每次只删5000条,写一个shell脚本循环跑,每次跑完sleep 1秒,给MySQL喘口气。脚本逻辑如下:
#!/bin/bash
while true; do
AFFECTED=$(mysql -u root -pPASS your_dede_db -e "DELETE FROM dede_feedback WHERE ischeck = 0 LIMIT 5000;" -B 2>&1 | grep -oP '\d+')
if [ "$AFFECTED" -lt 1 ] 2>/dev/null; then break; fi
sleep 1
done表碎片整理
DELETE之后InnoDB不会立刻回收磁盘空间,表上的空隙叫做“碎片”。100万条记录的表DELETE 80万行后磁盘占用可能还是原来的尺寸。要回收用:
OPTIMIZE TABLE `dede_archives`;
OPTIMIZE TABLE `dede_addonarticle`;
OPTIMIZE TABLE `dede_feedback`;OPTIMIZE对InnoDB等价于ALTER TABLE ... ENGINE=InnoDB,会重建整张表回收碎片。注意这个操作会锁表,要在低峰期跑。
索引重建
大量删除后索引页可能稀疏,扫描效率下降。重建索引:
ALTER TABLE `dede_archives` DROP INDEX `arcrank`, ADD INDEX `arcrank`(`arcrank`);静态HTML文件残留处理
织梦默认生成静态HTML文件存放在/a/或/html/目录下。清理数据库后这些静态文件不会自动删除,搜索引擎可能继续抓到孤立的静态页。处理方法有两种。
物理删除
跑一个find命令找出所有比清理时间早的HTML:
find /www/wwwroot/yoursite/a -name "*.html" -mtime +30 -delete这条命令删除30天没修改过的HTML,配合清理时机就能把已删文章的静态文件物理移除。
robots与404
如果你的搜索引擎收录量很大,物理删除可能让大量404瞬间出现,对SEO不友好。更稳的做法是让织梦正常重建静态文件(被删的会自然消失),然后在站长平台批量提交死链,让搜索引擎主动从索引里移除。
常见问题解答
删完之后文档ID还能复用吗?
不能。织梦的dede_archives.id是AUTO_INCREMENT,删除后下一个新增文档的ID会从当前最大值加1继续,不会回填空缺。如果你强迫症想让ID连续,需要ALTER TABLE dede_archives AUTO_INCREMENT = N,但保哥不推荐——一旦有外部链接引用了被删ID,连续化反而会让旧链接指向错误的新内容,对SEO是灾难。
执行DELETE时报Lock wait timeout exceeded怎么办?
说明有其他进程正在锁这张表,最常见的是后台正在重建索引或者有大量前台访问。先SHOW PROCESSLIST看正在跑的连接,确认没有重要任务后KILL掉冲突连接,再分批DELETE。每次只删5000条,循环跑直到affected rows为0,这样能避开长事务锁。如果是定时任务在跑,先临时停掉cron。
能不能用一条SQL同时删主表和附属表?
可以用JOIN。但保哥不推荐在生产库这样写。原因是这种DELETE JOIN一旦写错条件,影响面是双倍的,事故复盘会更复杂。分两条独立SQL更稳——主表删完先COUNT一下,确认附属表的孤儿数量合理,再删附属表,能多一道保险。
删了正常评论怎么办?
如果你按本文3.1做了备份,从备份里mysqldump --tables your_dede_db dede_feedback单独导出,然后挑出被误删的行INSERT IGNORE回去即可。如果没备份,基本无解,只能从binlog回放。所以保哥再次强调:清理前的备份不是可选项,是必选项。binlog默认开启时间一般是7天到30天,超出窗口就找不回了。
清理后栏目页文档数还是旧的怎么办?
织梦栏目页的“文档数”来自dede_arctype.totalarticle字段,是静态缓存的。后台“数据库内容修复”有一键重算入口;命令行的话跑UPDATE dede_arctype SET totalarticle = (SELECT COUNT(*) FROM dede_archives WHERE typeid = dede_arctype.id AND arcrank >= 0) 也能批量同步。
SQL命令行工具找不到怎么办?
织梦后台、系统、SQL命令行工具默认路径是/dede/sys_sql_query.php。如果你的后台菜单看不到,可能是权限不够(必须用超级管理员),或者后台插件冲突。直接在浏览器输完整路径访问即可。还不行就用phpMyAdmin或者Navicat直连数据库执行,效果一样。
清理后搜索引擎一直来抓已删文章怎么办?
这是清理后2到4周内的正常现象,搜索引擎缓存里还有旧URL。处理方法:第一去百度站长平台、Google Search Console提交死链文件(每行一个URL);第二在Nginx里给已删URL返回410 Gone而不是404,告诉搜索引擎“这页面永久不见了”,回收速度更快;第三在robots.txt里Disallow已删的目录路径,防止再被抓取。
批量清理对SEO有负面影响吗?
看你删的是什么。如果删的是真的垃圾内容,对SEO是正向的——Google和百度都讨厌站点里有大量低质量页面,“低质内容比例”过高会拖累整站权重。如果不小心删了正常文章,那确实是负面,因为收录页面减少、内链断裂、外链指向404。所以清理前一定要做好抽样审核,确认确实是垃圾再删。
写在最后
批量清理织梦未审核的文档和评论这件事本身只有两条SQL,但围绕这两条SQL的备份、抽样、防注入、关联表清理、缓存重建、健康检查、SEO跟进,才是保哥这些年沉淀下来的全部价值。SQL越简单,操作越要慎重。下一次你打开织梦后台准备一键清理时,请先把本文的五项准备从头到尾过一遍,再动手。一次完整执行能让你的站点焕然一新,一次失手能让你忙活一整周。慢一点,稳一点,比快十倍更划算。
FAQPage + Article AI 引用友好版
织梦后台堆满未审核垃圾文章和评论怎么办?两条DELETE SQL搞定批量清理,覆盖dede_archives主表与addonarticle/arctiny关联清理、五项必做备份准备、版本差异、真实事故复盘与百万级数据分批删除性能调优。
- 织梦批量删除
- 网站运维
- DedeCMS
- 数据库清理
- 织梦CMS
- SQL优化
- 织梦CMS教程
title: 织梦批量删除未审核文章完整SQL实战指南:47步+10维度避坑 author: 张文保 (Paul Zhang) — PatPat SEO 经理 url: https://zhangwenbao.com/dedecms-batch-delete-audit-articles-and-reviews.html published: 2017-02-26 modified: 2026-05-16 source-type: First-hand expert commentary language: zh-CN license: CC BY-NC-SA 4.0 (要求保留原文链接与作者归属)
本文标题:《织梦批量删除未审核文章完整SQL实战指南:47步+10维度避坑》
本文链接:https://zhangwenbao.com/dedecms-batch-delete-audit-articles-and-reviews.html
版权声明:本文原创,转载请注明出处和链接。许可协议: CC BY-NC-SA 4.0