2012-12-07 106 views
1

在我告訴查詢這裏有相關的表定義:SQL查詢慢於預期

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爲連接的任何是超級快,可以在任何時間完成所有假設所有相關列是主鍵和外鍵(在這是他們的情況)。

我嘗試了一些其他的疑問:

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?

+0

您應該指定您正在使用的數據庫和版本,方法是將其作爲問題中的標記。 –

+0

根據表格的內容,您會期望連接中的不平等條件花費比平等更長的時間。也許如果你在桌子上放一些指標,你會看到一個改進。 – Xophmeister

回答

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列中將會出現很多重複項,但由於我實際上沒有獲取該行,因此在該列中重複數據並不重要。

謝謝!

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

你看指標足以給我...你可以試試這個查詢,讓我知道如何性能與您的原始相比?

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的)必須檢查多少除正在搜索的海報外,海報的主題更少。

+0

我試過了,它也需要一段時間。當我做「SHOW FULL PROCESSLIST」時,查詢的狀態是「發送數據」。到目前爲止,它一直處於這種狀態幾百秒.. – neubert

+0

我不知道MySQL中的EXISTS/NOT EXISTS,但是 - 每天學習一些新東西! – neubert

+0

@neubert你能對原始查詢做一個'EXPLAIN',並用結果更新你的問題嗎? –