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 |
5 분마다 ~ 20 행으로 늘어나는 300k 행과 비슷합니다. 쿼리가 매우 자주 실행됩니다 (모든 페이지로드)
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 분석은 explain.depesz.com에 있습니다. 약 8s 걸립니다. 미친!
feed_url
에는 약 20 개의 고유 값이 있으므로 실제로는 비효율적입니다. 나는 어리 석고 함수에서 FOR 루프를 시도 할 것이라고 생각했다. 단지 307ms 소요
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');
!
SQL에서 FOR 루프를 사용하면 잘못된 방법으로 문안합니다. 첫 번째 문법처럼 효율적인 쿼리를 작성하는 방법은 무엇입니까? 그게 가능하니? 아니면 FOR 루프가 실제로 가장 좋은 곳입니까?
ETA
포스트 그레스 버전 : PostgreSQL의 9.1.5 (수세 리눅스) 4.3.4 [GCC-4_3 분기 개정 152,973] gcc에서 컴파일는 i686-PC-리눅스 GNU에 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);
그냥 @Cathy가 'work_mem'을 20MB로 늘리려고했는데 http://explain.depesz.com/s/UJw (지금 삭제 한 답변에 대한 의견)입니다. 정렬은 더 이상 디스크로 유출되지 않지만 쿼리가 크게 빠르지는 않습니다. 인덱스 만들기'CREATE INDEX feeds_up_feed_url_observed ON feed_up (feed_url, 관찰 된 DESC);도 좋지 않았다; 색인은 사용되지 않습니다. –
그런데 PostgreSQL 버전은 무엇입니까? 'SELECT 버전()'. –
@CraigRinger 9.1.5, 편집을하겠습니다. – Cathy