2009-07-07 8 views
6

MySQLを使用して自分のサイト用のカスタムフォーラムを構築しました。リストページは基本的に次の列を持つ表です:トピック最終更新日#返信MySQLクエリを最適化して「どこで使用するのか、一時的に使用するのか、filesortを使用するのか」

DBテーブルには、次の列があります。

id 
name 
body 
date 
topic_id 
email 

トピックは "0" のtopic_idを持っており、彼らの親トピックのtopic_idを持って回答。

SELECT SQL_CALC_FOUND_ROWS 
    t.id, t.name, MAX(COALESCE(r.date, t.date)) AS date, COUNT(r.id) AS replies 
FROM 
    wp_pod_tbl_forum t 
LEFT OUTER JOIN 
    wp_pod_tbl_forum r ON (r.topic_id = t.id) 
WHERE 
    t.topic_id = 0 
GROUP BY 
    t.id 
ORDER BY 
    date DESC LIMIT 0,20; 

この表には合計2,100個の項目があり、クエリには通常6秒かかります。私は "topic_id"列にINDEXを追加しましたが、それはあまり役に立ちませんでした。重要なリストラをしてこのクエリをスピードアップする方法はありますか?

EDIT:まだまだ未熟です。私は下の例を適切に働かせるようには見えない。

答えて

7
SELECT id, name, last_reply, replies 
FROM (
     SELECT topic_id, MAX(date) AS last_reply, COUNT(*) AS replies 
     FROM wp_pod_tbl_forum 
     GROUP BY 
       topic_id 
     ) r 
JOIN wp_pod_tbl_forum t 
ON  t.topic_id = 0 
     AND t.id = r.topic_id 
UNION ALL 
SELECT id, name, date, 0 
FROM wp_pod_tbl_forum t 
WHERE NOT EXISTS 
     (
     SELECT NULL 
     FROM wp_pod_tbl_forum r 
     WHERE r.topic_id = t.id 
     ) 
     AND t.topic_id = 0 
ORDER BY 
     date DESC 
LIMIT 0, 20 

あなたのテーブルがMyISAMまたはidある場合はPRIMARY KEYではありません、あなたは(topic_id, id)に複合ondexを作成する必要があります。

あなたのテーブルがInnoDBidPRIMARY KEYである場合は、行いますちょうど(topic_id)上のインデックス(idが暗黙のうちにインデックスに追加されます)。

更新

このクエリは、おそらく、より効率的になりますが、あなたが(topic_id, id)(date, id)のインデックスを有することを条件とする:

パフォーマンスの詳細については、私のブログにこの記事を参照してください。

このクエリは100,000行のサンプルデータに30 msで完了します。

SELECT id, name, last_reply, 
     (
     SELECT COUNT(*) 
     FROM wp_pod_tbl_forum fc 
     WHERE fc.topic_id = fl.topic_id 
     ) AS replies 
FROM (
     SELECT topic_id, date AS last_reply 
     FROM wp_pod_tbl_forum fo 
     WHERE id = (
       SELECT id 
       FROM wp_pod_tbl_forum fp 
       WHERE fp.topic_id = fo.topic_id 
       ORDER BY 
         fp.date DESC, fp.id DESC 
       LIMIT 1 
       ) 
       AND fo.topic_id <> 0 
     ORDER BY 
       fo.date DESC, fo.id DESC 
     LIMIT 20 
     ) fl 
JOIN wp_pod_tbl_forum ft 
ON  ft.id = fl.topic_id 
UNION ALL 
SELECT id, name, date, 0 
FROM wp_pod_tbl_forum t 
WHERE NOT EXISTS 
     (
     SELECT NULL 
     FROM wp_pod_tbl_forum r 
     WHERE r.topic_id = t.id 
     ) 
     AND t.topic_id = 0 
ORDER BY 
     last_reply DESC, id DESC 
LIMIT 20 

どちらのインデックスが効率的であると、このクエリのために必要とされます。

あなたのテーブルには、InnoDBidであれば、あなたは上記のindexesからIDを省略することができ、PRIMARY KEYです。

+0

フィールドリストの 'date'列が曖昧です..? – Matt

+0

@Matt:アップデートを参照 – Quassnoi

+0

@Quassnoi - 何が起こっているか説明できますか?トピックに返信がない場合、「UNION ALL」は「last_reply」を「date」に置き換えますか? – Matt

1

(内部クエリとして)サブクエリのセットに分割したい場合があります。私は実際にプレイするスキーマを必要とするだろうが、あなたはスピードを少しそれを助けるかもしれ

SELECT t.id, t.name, MAX(COALESCE(r.date, t.date)) AS date, COUNT(r.id) AS replies 
FROM (
    SELECT (id, name, date) 
    FROM wp_pod_tbl_forum 
    WHERE topic_id = 0 
) as t 
LEFT OUTER JOIN 
    wp_pod_tbl_forum r 
WHERE 
    r.topic_id = t.id 
GROUP BY 
    t.id 
ORDER BY 
    date DESC LIMIT 0,20; 

、それも最良の答えではないかもしれない場合(エラーが存在する可能性があります)。

これにはたくさんの方法がありますが、SQLチューニング時に最も重要なことは、操作を実行する前に各セットを可能な限り減らすことです。

関連する問題