という名前の PostgreSQL データベースにテーブルがありますfeeds_up
。次のようになります。
| feed_url | isup | hasproblems | observed timestamp with tz | id (pk)|
|----------|------|-------------|-------------------------------|--------|
| http://b.| t | f | 2013-02-27 16:34:46.327401+11 | 15235 |
| http://f.| f | t | 2013-02-27 16:31:25.415126+11 | 15236 |
30 万行程度で、5 分ごとに最大 20 行ずつ増えています。非常に頻繁に (ページの読み込みごとに) 実行されるクエリがあります。
select distinct on (feed_url) feed_url, isUp, hasProblems
from feeds_up
where observed <= '2013-02-27T05:38:00.000Z'
order by feed_url, observed desc;
そこに時間の例を入れました。その時間はパラメータ化されています。Explain Analyst はExplain.depesz.comにあります。約 8 秒かかります。クレイジー!
には約 20 の一意の値しかないためfeed_url
、これは非常に非効率的です。私は愚かで、関数で FOR ループを試してみようと思いました。
CREATE OR REPLACE FUNCTION feedStatusAtDate(theTime timestamp with time zone) RETURNS SETOF feeds_up AS
$BODY$
DECLARE
url feeds_list%rowtype;
BEGIN
FOR url IN SELECT * FROM feeds_list
LOOP
RETURN QUERY SELECT * FROM feeds_up
WHERE observed <= theTime
AND feed_url = url.feed_url
ORDER BY observed DESC LIMIT 1;
END LOOP;
END;
$BODY$ language plpgsql;
select * from feedStatusAtDate('2013-02-27T05:38:00.000Z');
わずか307msです。
SQL で FOR ループを使用すると、最初のクエリのように効率的な適切なクエリを作成するにはどうすればよいでしょうか。それは可能ですか?それとも、これは FOR ループが本当に最適な種類のものですか?
ETA
Postgres バージョン: i686-pc-linux-gnu 上の PostgreSQL 9.1.5、gcc (SUSE Linux) 4.3.4 [gcc-4_3-branch リビジョン 152973]、32 ビットでコンパイル
feeds_up のインデックス:
CREATE INDEX feeds_up_url
ON feeds_up
USING btree
(feed_url COLLATE pg_catalog."default");
CREATE INDEX feeds_up_url_observed
ON feeds_up
USING btree
(feed_url COLLATE pg_catalog."default", observed DESC);
CREATE INDEX feeds_up_observed
ON public.feeds_up
USING btree
(observed DESC);