なんかばんざい

会社や家で感じたもんのとある備忘録!!

それ単一SQLで出来るよ

*注意:勘違いでした。以下はまちがってます。

PostgreSQLだけど。MySQLはサブクエリが微妙だったはずなので出来るかわからない。

使用したバージョンはPostgreSQL 8.2ですが、それほど新しくないPostgreSQLでもいけると思う。

Kazuho@Cybozu Labs: フレンド・タイムライン処理の原理と実践

1. フォローしている各ユーザーについて、そのメッセージ ID の最大値を取得

2. 1 のリストをメッセージ ID の降順でソートし、その先頭 20 件 (1ページ分) 以外を破棄

3. 2 のリストの全ユーザーについて、最新 20 件のメッセージを取得し、マージ

4. 3 のリストの先頭 20 件が、クライアントに返すべきフレンド・タイムライン

テーブル定義はこんな感じ。serial型はinteger AUTO_INCREMENT(と同じとみなしていい)。

CREATE TABLE follower
(
  id serial NOT NULL,
  followed_user_id integer NOT NULL, -- フォローされてるユーザID
  following_user_id integer NOT NULL,-- フォローしてるユーザID
  CONSTRAINT follower_pkey PRIMARY KEY (id)
);


CREATE TABLE messages
(
  id serial NOT NULL,
  user_id integer NOT NULL,-- 発言した人のユーザID
  message character varying(255) NOT NULL,-- メッセージ本体。character varying=varchar
  CONSTRAINT messages_pkey PRIMARY KEY (id)
);

データを入れていく。user_id=1の人のフレンドタイムラインを構築する予定。

-- user_id=1の人が、user_id 2〜19までをフォローする。
-- 特に19である必要も連番である意味もない。

INSERT INTO follower (following_user_id,followed_user_id) VALUES
(1,2)
,(1,3)
,(1,4)
,(1,5)
,(1,6)
,(1,7)
,(1,8)
,(1,9)
,(1,10)
,(1,11)
,(1,12)
,(1,13)
,(1,14)
,(1,15)
,(1,16)
,(1,17)
,(1,18)
,(1,19);

/*
|following_user_id|followed_user_id|
|1|2|
|1|3|
|1|4|
|...|...|
|1|19|
 */

-- 以下のようなSQLを最低でも1000回くらいは繰り返してダミーデータ生成。

INSERT INTO messages (user_id,message) VALUES
(floor(random()*50)+1,random()::text); -- user_id 1〜50の発言をランダムに生成

準備が出来たらいよいよ取得。user_id BETWEEN 2 AND 19じゃないやつが出たら失敗。


select main.* from messages as main
inner join (
	select user_id
	from messages
	where user_id IN (
		select followed_user_id from follower where following_user_id=1 -- user_id=1の人のフレンドラインを取得するので。
	)
	group by user_id
	order by max(id) DESC -- 手順1:メッセージID最大値
	limit 20 -- 手順2:21件目以降は破棄する
) as tmp on (tmp.user_id=main.user_id) -- 手順3:マージ

order by id desc
limit 20 -- 手順4:結果20件

うまくいった(はず)。

ちなみに2回出てくるlimit 20と、following_user_id=1がそれぞれ変数になります。

ほか

メール

フォクすけ

Mozilla Firefox ブラウザ無料ダウンロード