2

我正在编写一个 cron 脚本(在 MySQL 数据库的 PHP PDS 中),它将从数据库中删除超过 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']));
    }
}   
4

5 回答 5

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是否可以保证有带有 that 的记录tablekey_id。如果是,您可以使用内部联接。

于 2013-02-21T16:33:21.590 回答
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

于 2013-02-21T16:25:37.497 回答
1

首先你想像现在一样检索 ID 列表,然后你想构造 4 个这样的查询:

DELETE FROM 'table' where 'id' IN ('id1', 'id2', 'id4')

这应该证明比单独删除更有效。它将查询数量减少到 5 而不是 1+ 4N

于 2013-02-21T16:28:33.820 回答
0

据我所知,PDO 只接受一个声明......

您可以查看从第一个(或您是主)表中删除的触发器...

于 2013-02-21T16:24:09.587 回答
-1

有时我用它来解决我的问题。首先将 ids 放入字符串中。

$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)");
于 2013-02-21T16:51:30.173 回答