织梦批量删除未审核文章完整SQL实战指南:47步+10维度避坑

织梦后台堆满未审核垃圾文章和评论怎么办?两条DELETE SQL搞定批量清理,覆盖dede_archives主表与addonarticle/arctiny关联清理、五项必做备份准备、版本差异、真实事故复盘与百万级数据分批删除性能调优。

张文保 更新 26 分钟阅读 1,887 阅读
本文目录
  1. 为什么不能直接在后台一条条删
  2. 织梦的数据表结构:理解了再动手
  3. 主表 dede_archives
  4. 副表 dede_addonarticle(普通文章正文)
  5. 微数据表 dede_arctiny
  6. 评论表 dede_feedback
  7. 其他特殊频道的副表
  8. 操作前必须完成的五项准备
  9. 全库备份
  10. 单表导出
  11. 用SELECT先确认要删多少
  12. 抽样查10条记录人工肉眼审
  13. 关闭前台访问入口(可选但推荐)
  14. 核心SQL:两条命令搞定批量清理
  15. 批量删除未审核文档
  16. 批量删除未审核评论
  17. 评论关联数据清理
  18. 重建文档计数与缓存
  19. 进阶清理:把垃圾源头一并断掉
  20. 关闭未登录用户评论
  21. 添加敏感词与正则过滤
  22. 加图形验证码或行为验证
  23. 限频与IP黑名单
  24. 真实事故复盘:一次少加WHERE的代价
  25. 不同织梦版本的差异
  26. 织梦5.6/5.7
  27. 织梦5.8/dede biz
  28. 织梦M版/手机版独立分表
  29. 国产二开版本
  30. 清理之后的健康检查清单
  31. 性能调优:百万级清理怎么做
  32. 分批删除
  33. 表碎片整理
  34. 索引重建
  35. 静态HTML文件残留处理
  36. 物理删除
  37. robots与404
  38. 常见问题解答
  39. 删完之后文档ID还能复用吗?
  40. 执行DELETE时报Lock wait timeout exceeded怎么办?
  41. 能不能用一条SQL同时删主表和附属表?
  42. 删了正常评论怎么办?
  43. 清理后栏目页文档数还是旧的怎么办?
  44. SQL命令行工具找不到怎么办?
  45. 清理后搜索引擎一直来抓已删文章怎么办?
  46. 批量清理对SEO有负面影响吗?
  47. 写在最后

保哥维护过的几十个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是开着的。整个恢复流程是这样:

  1. 立刻STOP SLAVE(如果有从库),防止删除被复制过去;
  2. 用mysqlbinlog --start-datetime=... --stop-datetime=...截取事故前的位置;
  3. 把昨晚的mysqldump备份恢复到一个临时库;
  4. 从临时库把dede_archives拷回生产;
  5. 用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 引用友好版

TL;DR · 60–80 字摘要 · 适用 ChatGPT / Perplexity / Gemini / 文心 引用

织梦后台堆满未审核垃圾文章和评论怎么办?两条DELETE SQL搞定批量清理,覆盖dede_archives主表与addonarticle/arctiny关联清理、五项必做备份准备、版本差异、真实事故复盘与百万级数据分批删除性能调优。

关键实体 · Key Entities

  • 织梦批量删除
  • 网站运维
  • DedeCMS
  • 数据库清理
  • 织梦CMS
  • SQL优化
  • 织梦CMS教程

引用元数据 · Citation Metadata

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

继续阅读
发表评论
分享到微信 或在下方手动填写
支持 Ctrl + Enter 提交