在我显示查询之前,这里是相关的表定义:
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秒之间)。如果我更改&lt;&gt;到a =它根本没有时间。
我做了一些不正确的假设吗?也许我的DB只是foobar'd?
答案 0 :(得分: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),
);
答案 1 :(得分: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
而不是LEFT JOIN
实现)将必须检查除被搜索者之外的海报的主题少得多。
答案 2 :(得分: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列中会有很多重复项,但由于我实际上没有得到那一行,我认为该列中的重复项并不重要。
谢谢!