0

これは phpBB から改変されたコードです。私が知る限り、唯一の投稿者がターゲットユーザーであるすべてのトピックを削除しようとしています。

(テスト目的で、最終クエリを DELETE から SELECT に変更したことに注意してください)

<?php
$user_id = 66275;

mysql_connect('localhost', 'username', 'password');
mysql_select_db('db_name');

$start = microtime(true);
$total = 0;

define('POSTS_TABLE', 'phpbb_posts');
define('TOPICS_TABLE', 'phpbb_topics');

         $sql = 'SELECT topic_id, COUNT(post_id) AS total_posts 
            FROM ' . POSTS_TABLE . " 
            WHERE poster_id = $user_id 
            GROUP BY topic_id"; 
         $result = mysql_query($sql);

         $topic_id_ary = array(); 
         while ($row = mysql_fetch_assoc($result)) 
         { 
            $topic_id_ary[$row['topic_id']] = $row['total_posts']; 
         } 
         mysql_free_result($result); 

         if (sizeof($topic_id_ary)) 
         { 
            $sql = 'SELECT topic_id, topic_replies, topic_replies_real 
               FROM ' . TOPICS_TABLE . ' 
               WHERE ' . sql_in_set('topic_id', array_keys($topic_id_ary)); 
            $result = mysql_query($sql); 

            $del_topic_ary = array(); 
            while ($row = mysql_fetch_assoc($result)) 
            { 
               if (max($row['topic_replies'], $row['topic_replies_real']) + 1 == $topic_id_ary[$row['topic_id']]) 
               { 
                  $del_topic_ary[] = $row['topic_id']; 
               } 
            } 
            mysql_free_result($result); 

            if (sizeof($del_topic_ary)) 
            { 
               $sql = 'SELECT topic_id FROM ' . TOPICS_TABLE . ' 
                  WHERE ' . sql_in_set('topic_id', $del_topic_ary); 
               $result = mysql_query($sql);
               while ($row = mysql_fetch_assoc($result)) 
               { 
$total++;
                  echo $row[topic_id] . "\r\n";
               } 
            } 
         }

    function sql_in_set($field, $array, $negate = false, $allow_empty_set = false)
    {
        if (!sizeof($array))
        {
            if (!$allow_empty_set)
            {
                // Print the backtrace to help identifying the location of the problematic code
                $this->sql_error('No values specified for SQL IN comparison');
            }
            else
            {
                // NOT IN () actually means everything so use a tautology
                if ($negate)
                {
                    return '1=1';
                }
                // IN () actually means nothing so use a contradiction
                else
                {
                    return '1=0';
                }
            }
        }

        if (!is_array($array))
        {
            $array = array($array);
        }

        if (sizeof($array) == 1)
        {
            @reset($array);
            $var = current($array);

            return $field . ($negate ? ' <> ' : ' = ') . $var;
        }
        else
        {
            return $field . ($negate ? ' NOT IN ' : ' IN ') . '(' . implode(', ', $array) . ')';
        }
    }



$elapsed = microtime(true) - $start;

echo "\r\ntook $elapsed seconds";
echo "\r\ngot $total rows back";
?>

これは 3 つのクエリを実行します。最初に、対象ユーザーが投稿したすべてのトピックと、各トピックへの投稿回数を取得します。2 番目は、最初のクエリの各トピックが実際に持っている返信の数を取得します。次に、対象ユーザーがすべての投稿を行ったトピックを確認するための PHP コードがあります。その後、コード (私の変更前) はこれらすべてのトピックを削除します。

全体として、これは次のようなことを行うことでより適切に記述できるように思えます。

SELECT t.topic_id 
FROM phpbb_topics AS t 
JOIN phpbb_posts AS p1
   ON p1.topic_id = t.topic_id
      AND p1.poster_id = $poster_id
LEFT JOIN phpbb_posts AS p2 
   ON p2.topic_id = t.topic_id 
      AND p2.poster_id <> $poster_id
WHERE p2.poster_id IS NULL;

または多分これ:

SELECT t.topic_id 
FROM phpbb_topics AS t 
JOIN phpbb_posts AS p1
   ON p1.topic_id = t.topic_id
      AND p1.poster_id = $poster_id
      AND t.topic_poster = $poster_id
      AND t.topic_last_poster_id = $poster_id
LEFT JOIN phpbb_posts AS p2 
   ON p2.topic_id = t.topic_id 
      AND p2.poster_id <> $poster_id
WHERE p2.poster_id IS NULL

これをテストすることは、 MySQL のキャッシングのおかげで実際には非常に困難ですが... 私が実行できたテストから、phpBB が現在行っている方法の方が実際には高速であるように思えます。これは私にとって驚くべきことです。

何か案は?

4

1 に答える 1

1

あなたが正しい軌道に乗っているように私には見えます。結合で使用しているすべての列にインデックスを追加してみてください。これにより、結合の速度が大幅に向上することがよくあります。

于 2012-12-08T20:10:11.143 に答える