[pgsql-jp: 41220] Re: 掲示板テーブルからのデータ取得について
Tomoaki Sato
sato @ sraoss.co.jp
2012年 9月 21日 (金) 23:11:07 JST
佐藤です。
> はじめまして、高田と申します。
>
> 現在バージョン8.1で掲示板を稼働させているのですが、効率良くデータを
> 取得する方法について教えていただきたいことがあります。
> テーブル構成は下記のような形となっております。
>
> テーブル名:bbs
> 項目:message_id(連番のメッセージID),response_to(返信先のメッセー
> ジID),name(投稿者名),title(件名),message(本文),created_at(投
> 稿日時)
>
> 上記のようなかたちで、通常の投稿はresponse_toがNULL、メッセージ
> ID「12」に対する返信投稿であればresponse_toに「12」が入ります。
> このテーブルからresponse_toがNULLのデータ(返信ではない投稿)の一覧
> を取得するのですが、その際の取得順は、返信がなければ投稿日時、返信が
> あれば最新の返信日時、が新しい順としています。
> 現状は下記のようなクエリにより取得しています。
> ※投稿データに加えて返信の件数、最新の返信日時も併せて取得しています
>
> SELECT
> bbs.*,
> ( select count(*) from bbs s1
> where response_to = bbs.message_id ) as count,
> case when j2.created_at is not null then j2.created_at
> else bbs.created_at end as latest_time
> FROM
> bbs
> LEFT JOIN
> (
> SELECT
> r1.response_to,r1.created_at
> FROM bbs r1
> LEFT JOIN bbs r2 ON r1.message_id < r2.message_id
> and r1.response_to is not null
> and r2.response_to is not null
> and r1.response_to = r2.response_to
> WHERE r1.response_to is not null
> GROUP BY r1.response_to,r1.created_at
> HAVING count(r2.*) = 0
> ) j2 ON bbs.message_id=j2.response_to
> WHERE bbs.response_to is null
> ORDER BY latest_time DESC
上記の SQL だと、直接返信された投稿しか見てないですが、そういう仕様で
OK なのでしょうか。
> 一件の投稿に対する返信の中で最も新しい(メッセージIDの値が大きい)も
> のの日時を取得する箇所で、かなり処理が重くなってしまいます。
> 上記のクエリでは最新の返信日時もSELECTしていますが、その順に並べられ
> れば特に取得する必要はありません。
>
> インデックスはmessage_id(主キー)とresponse_toの項目に対してそれぞ
> れ設定しておりますが、それ以外には特に設定しておりません。
>
> 効率の良い取得方法、もしくは高速にするための有効なインデックス設定案
> があればご教示いただけませんでしょうか。
> よろしくお願い致します。
以下の SQL でどうでしょうか。
SELECT b1.message_id,
b1.response_to,
b1.name,
b1.title,
b1.message,
b1.created_at,
count(b2.*) AS count,
coalesce(max(b2.created_at), b1.created_at) AS latest_time
FROM bbs AS b1
LEFT JOIN (
SELECT response_to,
created_at
FROM bbs
) AS b2
ON b1.message_id = b2.response_to
WHERE b1.response_to IS NULL
GROUP BY b1.message_id,
b1.response_to,
b1.name,
b1.title,
b1.message,
b1.created_at
ORDER BY latest_time DESC;
1 万件の投稿に対して 1 万件の返信、それら 2 万件の投稿に対して 2 万件
の返信、というのを繰り返し、合計 8 万件のデータを生成して SQL を実行し
てみました。
PostgreSQL 8.1 のデフォルトの設定のままで実行時間を 2000 ミリ秒から
600 ミリ秒、さらに work_mem を 32768 (32MB) に増やして 300 ミリ秒まで
短縮できました。
----
Tomoaki Sato <sato @ sraoss.co.jp>
SRA OSS, Inc. Japan
pgsql-jp メーリングリストの案内