Received: from localhost (unknown [200.46.204.184]) by postgresql.org (Postfix) with ESMTP id C4F669FB542 for ; Thu, 1 Nov 2007 10:09:11 -0300 (ADT) Received: from postgresql.org ([200.46.204.71]) by localhost (mx1.hub.org [200.46.204.184]) (amavisd-maia, port 10024) with ESMTP id 12107-03 for ; Thu, 1 Nov 2007 10:08:56 -0300 (ADT) X-Greylist: from auto-whitelisted by SQLgrey-1.7.5 Received: from melon.pingpong.net (melon.pingpong.net [195.178.174.161]) by postgresql.org (Postfix) with ESMTP id 80F949F9870 for ; Thu, 1 Nov 2007 10:07:57 -0300 (ADT) Received: from localhost (localhost.pingpong.net [127.0.0.1]) by melon.pingpong.net (Postfix) with ESMTP id D9385509CB for ; Thu, 1 Nov 2007 14:08:00 +0100 (CET) Received: from melon.pingpong.net ([127.0.0.1]) by localhost (melon.pingpong.net [127.0.0.1]) (amavisd-new, port 10024) with LMTP id 48398-02-12 for ; Thu, 1 Nov 2007 14:08:00 +0100 (CET) Received: from [192.168.1.187] (unknown [213.136.40.204]) by melon.pingpong.net (Postfix) with ESMTP id A4C305084F for ; Thu, 1 Nov 2007 14:08:00 +0100 (CET) Date: Thu, 01 Nov 2007 14:07:55 +0100 From: Palle Girgensohn To: pgsql-performance@postgresql.org Subject: select max(field) from table much faster with a group by clause? Message-ID: X-Mailer: Mulberry/4.0.8 (Linux/x86) MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii; FORMAT=flowed Content-Transfer-Encoding: 7bit Content-Disposition: inline X-Virus-Scanned: by amavisd-new at pingpong.net X-Virus-Scanned: Maia Mailguard 1.0.1 X-Archive-Number: 200711/10 X-Sequence-Number: 27425 Hi, I have a table "login" with approx 600,000 tuples, a person table with approx 100000 tuples. When running select max("when") from login where userid='userid' it takes a second or two, but when adding "group by userid" the planner decides on using another plan, and it gets *much* faster. See example below. Number of tuples per user varies from zero to a couple of thousands. It seems to slower when there are no tuples as all, but it is always slow. This is only for max() and min(). For count(), the plan is the same, it always uses "Aggregate". Any ideas about this? Do we need to add "group by userid" to our code base to optimize, or is there another way? Updating postgresql to 8.2 is a long term option, but I'd like a short term option as well... Regards, Palle pp=# select version(); version ------------------------------------------------------------------------------------------------- PostgreSQL 8.1.8 on amd64-portbld-freebsd6.1, compiled by GCC cc (GCC) 3.4.4 [FreeBSD] 20050518 (1 row) Time: 0,530 ms pp=# explain analyze SELECT max("when") FROM login WHERE userid='girgen' ; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------ Result (cost=323.80..323.81 rows=1 width=0) (actual time=3478.781..3478.785 rows=1 loops=1) InitPlan -> Limit (cost=0.00..323.80 rows=1 width=8) (actual time=3478.768..3478.768 rows=0 loops=1) -> Index Scan Backward using login_when_idx on "login" (cost=0.00..131461.90 rows=406 width=8) (actual time=3478.759..3478.759 rows=0 loops=1) Filter: (("when" IS NOT NULL) AND (userid = 'sarah.gilliam1'::text)) Total runtime: 3478.868 ms (6 rows) Time: 3480,442 ms pp=# explain analyze SELECT max("when") FROM login WHERE userid='girgen' group by userid; QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------- GroupAggregate (cost=0.00..648.44 rows=1 width=25) (actual time=0.191..0.191 rows=0 loops=1) -> Index Scan using login_userid_idx on "login" (cost=0.00..646.40 rows=406 width=25) (actual time=0.183..0.183 rows=0 loops=1) Index Cond: (userid = 'sarah.gilliam1'::text) Total runtime: 0.243 ms (4 rows) Time: 0,938 ms pp=# \d login Table "public.login" Column | Type | Modifiers --------+--------------------------+-------------------- userid | text | kursid | integer | when | timestamp with time zone | mode | text | default 'pm'::text Indexes: "login_kurs_user_idx" btree (kursid, userid) "login_userid_idx" btree (userid) "login_when_idx" btree ("when") Foreign-key constraints: "pp_fk1" FOREIGN KEY (userid) REFERENCES person(userid) ON UPDATE CASCADE ON DELETE CASCADE "pp_fk2" FOREIGN KEY (kursid) REFERENCES course(id) ON UPDATE CASCADE ON DELETE CASCADE