1

在我在这里显示查询之前是相关的表定义:

CREATE TABLE phpbb_posts (
    topic_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
    poster_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
    KEY topic_id (topic_id),
    KEY poster_id (poster_id),
);


CREATE TABLE phpbb_topics (
    topic_id mediumint(8) UNSIGNED NOT NULL auto_increment
);

这是我要执行的查询:

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

基本上,该查询试图查找除目标用户以外的其他人发布的次数为零的所有主题。换句话说,唯一发帖的人就是目标用户的话题。

问题是查询需要很长时间。这是它的解释:

Array
(
    [id] => 1
    [select_type] => SIMPLE
    [table] => t
    [type] => index
    [possible_keys] =>
    [key] => topic_approved
    [key_len] => 1
    [ref] =>
    [rows] => 146484
    [Extra] => Using index
)
Array
(
    [id] => 1
    [select_type] => SIMPLE
    [table] => p
    [type] => ref
    [possible_keys] => topic_id,poster_id,tid_post_time
    [key] => tid_post_time
    [key_len] => 3
    [ref] => db_name.t.topic_id
    [rows] => 1
    [Extra] => Using where; Not exists
)

对于 SQL,我的一般假设是任何 JOIN 都非常快,并且可以在所有相关列都是主键或外键(在本例中是)的情况下立即完成。

我尝试了其他一些查询:

SELECT COUNT(1) 
    FROM phpbb_topics AS t 
    JOIN phpbb_posts AS p 
        ON p.topic_id = t.topic_id;

很快就会返回 353340。

然后我做这些:

SELECT COUNT(1) 
    FROM phpbb_topics AS t 
    JOIN phpbb_posts AS p 
        ON p.topic_id = t.topic_id
            AND p.poster_id <> 77198;

SELECT COUNT(1) 
    FROM phpbb_topics AS t 
    JOIN phpbb_posts AS p 
        ON p.topic_id = t.topic_id
    WHERE p.poster_id <> 77198;

这两个都需要相当长的时间(15-30秒之间)。如果我将 <> 更改为 a = 则根本不需要时间。

我做了一些不正确的假设吗?也许我的数据库只是 foobar'd?

4

3 回答 3

1

我认为将索引替换phpbb_posts(topic_id)为 2 个字段上的复合索引应该可以提高查询的性能:

CREATE TABLE phpbb_posts (
topic_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
poster_id mediumint(8) UNSIGNED DEFAULT '0' NOT NULL,
--KEY topic_id (topic_id), 
KEY topic_id_poster_id (topic_id,poster_id)
KEY poster_id (poster_id),
);
于 2012-12-07T17:02:53.307 回答
1

你的索引对我来说已经足够了......你能试试这个查询,让我知道性能与你原来的比较吗?

SELECT sub.topic_id
FROM (
    SELECT t.topic_id
    FROM phpbb_topics AS t 
    WHERE
        EXISTS (
            SELECT *
            FROM phpbb_posts p
            WHERE 
                p.topic_id = t.topic_id
                AND p.poster_id = 77198
        )
) sub
WHERE 
    NOT EXISTS (
        SELECT *
        FROM phpbb_posts p
        WHERE 
            p.topic_id = sub.topic_id
            AND p.poster_id <> 77198
)

我的想法是,通过将主题限制为仅相关海报实际发布的主题,反加入(在这种情况下使用NOT EXISTS而不是 a 实现LEFT JOIN)将必须检查的海报主题要少得多,而不是搜索。

于 2012-12-07T17:07:51.203 回答
0
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

这让它快了一吨。我正在获取目标用户发布的所有帖子,并附有主题信息,然后获取除目标用户之外的所有发布者。

p1.poster_id 列中会有很多重复项,但是由于我实际上没有得到该行,因此我认为该列中的重复项并不重要。

谢谢!

于 2012-12-07T20:36:27.753 回答