这个phpbb查询可以优化吗?

时间:2012-12-08 19:50:06

标签: mysql sql phpbb

这是一些改编自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

由于MySQLs caching测试这实际上非常困难,但是...从我能够做的测试看起来像phpBB目前正在做的方式实际上更快。这让我很惊讶。

有什么想法吗?

1 个答案:

答案 0 :(得分:1)

我认为你走在正确的轨道上。尝试将索引添加到您在联接中使用的所有列,因为这通常会大大提高连接速度。