我正在开发一个cron脚本(在PHP PDS中用于MySQL数据库),它将从数据库中删除超过30天的数据。香港专业教育学院曾尝试加入和删除级联我的表和语句,但他们没有成功,所以我采用一种更简单的方法来使其工作,但我知道这不是最有效的处理器方法。
请注意,其中一些表格(尤其是链接表格)有数十万行,这就是为什么我想要比我在这里更聪明一点。
表结构很简单,有一个表键表,有一个时间戳和一个id。该id在所有表中重复为tablekey_id
。
我目前的cron工作如下。
/* Cron script to delete old data from the database. */
if (@include dirname(dirname(dirname(__FILE__))) . '/dbconn/website_connections.php') {
$conn = $connectionFromOtherFile;
$keyTable = 'table_key';
$linksTable = 'links';
$domainsTable = 'link_domains';
$terms = 'searched_domains';
$query = $conn->query("SELECT `id` FROM `$keyTable` WHERE `timestamp` < (NOW() - INTERVAL 30 DAY)");
$query->setFetchMode(PDO::FETCH_ASSOC);
while($row = $query->fetch()) {
$conn->exec("DELETE FROM `$linksTable` WHERE `tablekey_id` = $row[id]");
$conn->exec("DELETE FROM `$domainsTable` WHERE `tablekey_id` = $row[id]");
$conn->exec("DELETE FROM `$terms` WHERE `tablekey_id` = $row[id]");
$conn->exec("DELETE FROM `$keyTable` WHERE `id` = $row[id]");
}
}
有没有办法将其纳入一个陈述?请谢谢你的帮助。
编辑:这是我最终的结果。/* Cron script to delete old data from the database. */
if (@include dirname(dirname(dirname(__FILE__))) . '/dbconn/website_connections.php') {
$conn = $connectionFromOtherFile;
$keyTable = 'table_key';
$linksTable = 'links';
$domainsTable = 'link_domains';
$terms = 'searched_domains';
$delete = $conn->prepare("DELETE tablekey, linktable, domaintable, searched
FROM `$keyTable` AS tablekey
LEFT OUTER JOIN `$linksTable` AS linktable on tablekey.id = linktable.tablekey_id
LEFT OUTER JOIN `$domainsTable` AS domaintable on tablekey.id = domaintable.tablekey_id
LEFT OUTER JOIN `$terms` AS searched on tablekey.id = searched.tablekey_id
WHERE tablekey.id = :tablekey_id");
$query = $conn->query("SELECT `id` FROM `$keyTable` WHERE `timestamp` < (NOW() - INTERVAL 30 DAY)");
$query->setFetchMode(PDO::FETCH_ASSOC);
while($row = $query->fetch()) {
$delete->execute(array('tablekey_id' => $row['id']));
}
}
答案 0 :(得分:5)
您应该可以使用以下一个查询删除:
DELETE kt, lt, dt, t
FROM `$keyTable` AS kt
LEFT OUTER JOIN `$linksTable` AS lt on kt.id = lt.tablekey_id
LEFT OUTER JOIN `$domainsTable` AS dt on kt.id = dt.tablekey_id
LEFT OUTER JOIN `$terms` AS t on kt.id = t.tablekey_id
WHERE kt.id = $row[id]
请注意,我在这里使用了外连接,因为我不确定keyTable
以外的表是否可以保证具有tablekey_id
的记录。如果是,则可以使用内连接。
答案 1 :(得分:1)
如果tablekey_id被编入索引,即使有数千行,这也应该没问题。如果你想保持你的数据库模式简单,我会保留4个查询,删除不是CPU密集型。 如果你真的想要一个语句,你将不得不复杂化并使用带有外键约束的级联删除:
CASCADE:从父表中删除或更新行,并自动删除或更新子表中匹配的行。支持ON DELETE CASCADE和ON UPDATE CASCADE。在两个表之间,不要定义几个ON UPDATE CASCADE子句,这些子句作用于父表或子表中的同一列。
来源:http://dev.mysql.com/doc/refman/5.5/en/innodb-foreign-key-constraints.html
这是承认您的数据库是innoDB
答案 2 :(得分:1)
首先,您要检索您现在正在执行的ID列表,然后您想要构建4个这样的查询:
DELETE FROM 'table' where 'id' IN ('id1', 'id2', 'id4')
这应该证明比单独删除更有效。它会将查询量减少到5而不是1 + 4N
答案 3 :(得分:0)
据我所知,PDO只接受一个声明......
你可以看一下从第一个(或你是主要的)表中删除的触发器......
答案 4 :(得分:-1)
有时候我用它来解决我的问题。首先将ID放在字符串中。
$ids = array();
while($row = $query->fetch()) {
$ids[] = $row[id];
}
$ids_str = implode(',', $ids);
$conn->exec("DELETE FROM `$linksTable` WHERE `tablekey_id` in ($ids_str) ");
$conn->exec("DELETE FROM `$domainsTable` WHERE `tablekey_id` in ($ids_str)");
$conn->exec("DELETE FROM `$terms` WHERE `tablekey_id` in ($ids_str)");
$conn->exec("DELETE FROM `$keyTable` WHERE `id` in ($ids_str)");