本文目录导读:

我来为您设计一个完整的PHP大表数据清理定时任务方案。
基础架构设计
主清理脚本 cleanup.php
<?php
/**
* 大表数据清理定时任务
* 支持分片删除、进度记录、异常恢复
*/
class LargeTableCleaner {
private $pdo;
private $config;
private $logFile;
public function __construct($config) {
$this->config = $config;
$this->logFile = $config['log_file'] ?? '/var/log/cleanup.log';
$this->initDatabase();
}
private function initDatabase() {
try {
$this->pdo = new PDO(
sprintf(
"mysql:host=%s;dbname=%s;charset=utf8mb4",
$this->config['db']['host'],
$this->config['db']['database']
),
$this->config['db']['username'],
$this->config['db']['password'],
[
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_TIMEOUT => 60
]
);
} catch (PDOException $e) {
$this->log("Database connection failed: " . $e->getMessage(), 'ERROR');
exit(1);
}
}
public function run() {
$startTime = microtime(true);
$this->log("开始清理任务");
try {
foreach ($this->config['tables'] as $tableConfig) {
$this->cleanTable($tableConfig);
}
$execTime = round(microtime(true) - $startTime, 2);
$this->log("清理任务完成,耗时: {$execTime}秒");
} catch (Exception $e) {
$this->log("清理失败: " . $e->getMessage(), 'ERROR');
$this->notifyAdmin($e->getMessage());
}
}
private function cleanTable($tableConfig) {
$tableName = $tableConfig['name'];
$condition = $tableConfig['condition'];
$batchSize = $tableConfig['batch_size'] ?? 5000;
$maxTotal = $tableConfig['max_total'] ?? PHP_INT_MAX;
$this->log("开始清理表: {$tableName}");
$deletedTotal = 0;
$continue = true;
while ($continue && $deletedTotal < $maxTotal) {
// 计算当前批次实际删除数量
$currentBatchSize = min($batchSize, $maxTotal - $deletedTotal);
// 执行删除
$deleted = $this->deleteBatch($tableName, $condition, $currentBatchSize);
$deletedTotal += $deleted;
$this->log("表 {$tableName} 已删除: {$deletedTotal} 条记录");
// 检查是否需要继续
if ($deleted < $batchSize) {
$continue = false;
}
// 检查超时
if ($this->isTimeout()) {
$this->log("达到时间限制,暂停清理");
break;
}
// 暂停,减轻数据库压力
usleep(500000); // 0.5秒
}
$this->log("表 {$tableName} 清理完成,共删除: {$deletedTotal} 条记录");
}
private function deleteBatch($tableName, $condition, $limit) {
try {
// 使用主键批量删除,效率更高
$sql = sprintf(
"DELETE FROM `%s` WHERE id IN (
SELECT id FROM (
SELECT id FROM `%s` WHERE %s LIMIT %d
) tmp
)",
$tableName,
$tableName,
$condition,
$limit
);
$stmt = $this->pdo->prepare($sql);
$stmt->execute();
return $stmt->rowCount();
} catch (PDOException $e) {
// 如果IN子查询方式失败,回退到简单删除
try {
$sql = sprintf(
"DELETE FROM `%s` WHERE %s LIMIT %d",
$tableName,
$condition,
$limit
);
$stmt = $this->pdo->prepare($sql);
$stmt->execute();
return $stmt->rowCount();
} catch (PDOException $e2) {
$this->log("删除失败: " . $e2->getMessage(), 'ERROR');
return 0;
}
}
}
private function isTimeout() {
if ($this->config['max_execution_time'] === null) {
return false;
}
static $startTime = null;
if ($startTime === null) {
$startTime = time();
}
return (time() - $startTime) >= $this->config['max_execution_time'];
}
private function log($message, $level = 'INFO') {
$logMessage = sprintf(
"[%s] [%s] %s\n",
date('Y-m-d H:i:s'),
$level,
$message
);
file_put_contents($this->logFile, $logMessage, FILE_APPEND | LOCK_EX);
echo $logMessage;
}
private function notifyAdmin($message) {
// 发送邮件或通知管理员
if (!empty($this->config['admin_email'])) {
mail(
$this->config['admin_email'],
'数据清理失败警报',
"失败时间: " . date('Y-m-d H:i:s') . "\n失败信息: " . $message
);
}
}
}
配置文件 config.php
<?php
return [
'db' => [
'host' => 'localhost',
'database' => 'your_database',
'username' => 'your_username',
'password' => 'your_password'
],
'log_file' => '/var/log/cleanup.log',
'admin_email' => 'admin@example.com',
'max_execution_time' => 1800, // 30分钟
'lock_file' => '/tmp/cleanup.lock',
'tables' => [
// 示例1:日志表
[
'name' => 'operation_logs',
'condition' => "created_at < DATE_SUB(NOW(), INTERVAL 90 DAY)",
'batch_size' => 5000,
'max_total' => 1000000
],
// 示例2:临时数据表
[
'name' => 'temp_data',
'condition' => "expire_time < NOW()",
'batch_size' => 10000,
'max_total' => PHP_INT_MAX
],
// 示例3:旧订单表
[
'name' => 'old_orders',
'condition' => "status = 'cancelled' AND created_at < DATE_SUB(NOW(), INTERVAL 365 DAY)",
'batch_size' => 3000,
'max_total' => 500000
]
]
];
主入口脚本 cleanup_main.php
<?php
/**
* 清理任务主入口
* 支持多种运行模式
*/
require_once 'config.php';
require_once 'cleanup.php';
class CleanerManager {
private $config;
private $lockFile;
public function __construct($config) {
$this->config = $config;
$this->lockFile = $config['lock_file'] ?? '/tmp/cleanup.lock';
}
public function execute() {
// 防止重复运行
if (!$this->acquireLock()) {
echo date('Y-m-d H:i:s') . " 已有清理任务在运行\n";
exit(1);
}
try {
// 创建清理器实例
$cleaner = new LargeTableCleaner($this->config);
$cleaner->run();
} finally {
$this->releaseLock();
}
}
private function acquireLock() {
// 使用 flock 实现进程锁
$fp = fopen($this->lockFile, 'w');
if ($fp === false) {
return false;
}
if (!flock($fp, LOCK_EX | LOCK_NB)) {
fclose($fp);
return false;
}
// 存储文件指针
$this->lockFp = $fp;
return true;
}
private function releaseLock() {
if (isset($this->lockFp) && is_resource($this->lockFp)) {
flock($this->lockFp, LOCK_UN);
fclose($this->lockFp);
}
}
}
// 执行清理
$manager = new CleanerManager($config);
$manager->execute();
清理进度记录脚本 show_progress.php
<?php
/**
* 查看清理进度
*/
class ProgressViewer {
private $pdo;
private $config;
public function __construct($config) {
$this->config = $config;
$this->initDatabase();
}
private function initDatabase() {
$this->pdo = new PDO(
sprintf(
"mysql:host=%s;dbname=%s;charset=utf8mb4",
$this->config['db']['host'],
$this->config['db']['database']
),
$this->config['db']['username'],
$this->config['db']['password']
);
}
public function showTableStats() {
echo "=== 表数据清理统计 ===\n\n";
foreach ($this->config['tables'] as $tableConfig) {
$tableName = $tableConfig['name'];
// 获取当前表的数据量
$sql = "SELECT COUNT(*) as total FROM `{$tableName}`";
$stmt = $this->pdo->query($sql);
$total = $stmt->fetch(PDO::FETCH_ASSOC)['total'];
// 获取满足清理条件的数据量
$condition = $tableConfig['condition'];
$sql = "SELECT COUNT(*) as count FROM `{$tableName}` WHERE {$condition}";
$stmt = $this->pdo->query($sql);
$deletable = $stmt->fetch(PDO::FETCH_ASSOC)['count'];
printf(
"表: %-20s 总量: %-15d 可清理: %-15d 清理比例: %.2f%%\n",
$tableName,
$total,
$deletable,
($deletable / max($total, 1)) * 100
);
}
}
}
$config = require 'config.php';
$viewer = new ProgressViewer($config);
$viewer->showTableStats();
Cron 配置示例
# crontab 配置 # 每天凌晨2点执行,清理超过90天的数据 0 2 * * * /usr/bin/php /path/to/cleanup_main.php >> /var/log/cleanup_cron.log 2>&1 # 也可以使用 systemd timer 方式 # 创建 /etc/systemd/system/db-cleanup.service [Unit] Description=Database Cleanup Service [Service] Type=oneshot ExecStart=/usr/bin/php /path/to/cleanup_main.php User=www-data # 创建 /etc/systemd/system/db-cleanup.timer [Unit] Description=Database Cleanup Timer [Timer] OnCalendar=*-*-* 02:00:00 Persistent=true [Install] WantedBy=timers.target
中断恢复机制
<?php
/**
* 断点续传处理
*/
class ResumeCleaner {
private $pdo;
private $progressTable = 'cleanup_progress';
public function saveProgress($tableName, $lastId, $deletedCount) {
$sql = "INSERT INTO {$this->progressTable}
(table_name, last_id, deleted_count, update_time)
VALUES (?, ?, ?, NOW())
ON DUPLICATE KEY UPDATE
last_id = VALUES(last_id),
deleted_count = deleted_count + VALUES(deleted_count),
update_time = NOW()";
$stmt = $this->pdo->prepare($sql);
$stmt->execute([$tableName, $lastId, $deletedCount]);
}
public function getProgress($tableName) {
$sql = "SELECT * FROM {$this->progressTable} WHERE table_name = ?";
$stmt = $this->pdo->prepare($sql);
$stmt->execute([$tableName]);
return $stmt->fetch(PDO::FETCH_ASSOC);
}
public function getLastDeleteId($tableName) {
$progress = $this->getProgress($tableName);
return $progress['last_id'] ?? 0;
}
}
最佳实践建议
1 性能优化
- 分批删除:避免大事务,每批5000-10000条
- 索引优化:确保清理条件字段有索引
- 低峰期执行:设置在工作负载较低的时段
- 连接池:使用持久连接减少连接开销
2 监控指标
// 记录性能指标
$this->log("批次删除: {$deleted} 条, 耗时: {$time}ms, 平均速度: " .
round($deleted / $time, 2) . "条/ms");
3 故障处理
// 异常重试机制
private function retryDelete($tableName, $condition, $limit, $retries = 3) {
for ($i = 0; $i < $retries; $i++) {
try {
return $this->deleteBatch($tableName, $condition, $limit);
} catch (Exception $e) {
$this->log("删除异常(第{$i+1}次尝试): " . $e->getMessage(), 'WARNING');
sleep(2);
}
}
return 0;
}
这个方案提供了完整的大表数据清理解决方案,包括分批处理、断点恢复、监控统计、任务锁等功能,确保数据清理任务安全、高效地运行。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播