Перебор строк в базе данных и их удаление - PullRequest
1 голос
/ 24 августа 2009

Я просто хотел бы проверить, является ли это хорошим способом перебирать строки в базе данных и удалять их при обработке? У меня сначала было

  • Хватай все
  • Обрабатывать все
  • Удалить все

Но подумал, что это может привести к проблемам, если новые строки были добавлены (извне), пока выполняется шаг «Обрабатывать все».

// the limited for loop is to prevent an infinite loop
// assume the limit to be much higher than the expected
// number of rows to process
for ($i = 0; $i < $limit; $i++) 
{

    // get next mail in queue
    $st = $db->prepare('
        SELECT id, to, subject, message, attachment
        FROM shop_mailqueue
        LIMIT 0,1
    ');
    $st->execute();
    $mail = $st->fetch(PDO::FETCH_ASSOC);

    // if no more mails in queue, stop
    if ($mail === false) {
        break;
    }

    // send queued mail
    $mailer = new PHPMailer();
    $mailer->AddAddress($mail['to']);
    $mailer->SetFrom('info@xxx.nl', 'xxx.nl');
    $mailer->Subject = $mail['subject'];
    $mailer->Body = $mail['message'];
    $mailer->AddAttachment($mail['attachment']);
    $mailer->Send();

    // remove mail from queue
    $st = $db->prepare('
        DELETE FROM shop_mailqueue WHERE id = :id
    ');
    $st->bindValue('id', $mail['id']);
    $st->execute();

}

Ответы [ 4 ]

2 голосов
/ 24 августа 2009

Я думаю, что вы схватите все, обработайте все, удалите все подход, просто изменение:

  • Вместо простого delete from table, сделайте delete from table where key in (<all keys retrieved>).

Вы можете легко создать <все ключи извлечены>, потому что вы сначала захватываете все.

Это будет работать (намного) лучше, чем выполнение многих запросов, как вы планируете делать сейчас.

1 голос
/ 24 августа 2009

Прежде всего, в любое время, когда вы говорите: «Итерация по строкам из базы данных», вам лучше говорить о какой-то очень сложной операции, выполняемой для каждой строки. В противном случае вы можете и должны думать в наборах!

Похоже, вы берете все в почтовую очередь и сбрасываете таблицу после отправки всех писем. Теперь я должен отметить, что ваш limit 0,1 немного сбивает с толку, так как у вас нет order by. Ни одна база данных не хранит вещи в надежном порядке (и на то есть веские причины - она ​​должна постоянно перемещать вещи для их оптимизации) Итак, лучший код будет:

// get next mail in queue
$st = $db->prepare('
    SELECT id, to, subject, message, attachment
    FROM shop_mailqueue
    ORDER BY id ASC
    LIMIT 0, ' . $limit);
        $st->execute();

$lastid = 0;

while ($mail = $st->fetch(PDO::FETCH_ASSOC))
{    
    // send queued mail
    $mailer = new PHPMailer();
    $mailer->AddAddress($mail['to']);
    $mailer->SetFrom('info@xxx.nl', 'xxx.nl');
    $mailer->Subject = $mail['subject'];
    $mailer->Body = $mail['message'];
    $mailer->AddAttachment($mail['attachment']);
    $mailer->Send();

    $lastid = $mail['id'];
}


// remove mail from queue
$st = $db->prepare('DELETE FROM shop_mailqueue WHERE id <= ' . $lastid);
$st->execute();

Таким образом, вы делаете только два (считайте их!) Запроса к базе данных, что на намного более оптимально, чем каждый раз возвращать одну строку назад.

Теперь, если вся сделка $limit не нужна, и вы действительно хотите откатить все строки в очереди, а затем просто вывести ее из очереди, измените свой оператор delete на:

TRUNCATE TABLE shop_mailqueue

Видите, truncate не связан логикой транзакции, а просто стирает таблицу, не задавая вопросов. Поэтому это очень быстро (как в миллисекундах, независимо от размера таблицы). delete просто не имеет такой скорости. Просто помните, что truncate - это ядерный вариант - как только вы truncate, он исчезнет.

0 голосов
/ 24 августа 2009

То, что ты делаешь, прекрасно, я думаю. Вы выбираете все, что у вас было, вы обрабатываете их и удаляете только те, которые вы обработали. Я также не стал бы блокировать таблицу в вашем процессе, потому что вы будете блокировать тех, кто создает записи.

Если единственная проблема, с которой вы столкнулись, - это обработка сообщений электронной почты, которые могли быть созданы при отправке существующих, тогда вы можете просто создать цикл while поверх всей вашей процедуры, чтобы он выполнялся всегда, когда новые записи.

Кроме того, зачем получать LIMIT 0,1 ($limit) раз, если вы можете просто изменить запрос, чтобы получить максимум $ limit элементов в одном запросе LIMIT 0,$limit.

0 голосов
/ 24 августа 2009

Вы можете заблокировать таблицу во время процесса

http://dev.mysql.com/doc/refman/5.0/en/lock-tables.html

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...