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;

基本的には、対象ユーザー以外の投稿回数がゼロのトピックをすべて検索するクエリです。つまり、対象ユーザーのみが投稿したトピックです。

問題は、クエリに非常に長い時間がかかることです。EXPLAIN は次のとおりです。

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 に関する私の一般的な仮定は、関連するすべての列が主キーまたは外部キー (この場合はそうである) であると仮定すると、any の 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 = に変更すると、まったく時間がかかりません。

私はいくつかの間違った仮定をしていますか? 多分私のDBはただの愚か者ですか?

4

3 に答える 3

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 に答える
1

インデックスを 2 つのフィールドの複合インデックスに置き換えるphpbb_posts(topic_id)と、クエリのパフォーマンスが向上すると思います。

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 に答える
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

それはそれを1トン速くしました。ターゲットユーザーが投稿したトピック情報が添付されたすべての投稿を取得してから、ターゲット以外のすべての投稿者を取得しています。

p1.poster_id列には多くの重複がありますが、実際にはその行を取得していないので、その列の重複はそれほど重要ではないと思います。

ありがとう!

于 2012-12-07T20:36:27.753 に答える