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";
?>

这会执行三个查询。首先获取目标用户发布的所有主题以及他们在每个主题中发布的次数。第二个获取第一个查询中每个主题实际有多少回复。然后有一些 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 回答