Search Postgresql Archives

Re: Selecting max(pk) is slow on empty set

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Alexander Staubo wrote:
On 1/22/08, Richard Huxton <dev@xxxxxxxxxxxx> wrote:
Alexander Staubo wrote:
# explain analyze select max(id) from user_messages where user_id = 13604;

         QUERY PLAN
        ------------------------------------------------------------------------------------------------------------------------------------------------------
Result  (cost=633.19..633.20 rows=1 width=0) (actual
time=339160.704..339160.704 rows=1 loops=1)

Do you have an index on user_id? Presumably that's what's being used in
the case of SELECT * or count(*).

Yes, I do. However, for some reason it's not being used here. The
index is clustered -- but I haven't run "cluster" on it recently. Does
that matter?

The index is still an index...

What cost does the count(*) come up with?

# explain analyze select count(*) from user_messages where user_id = 13604;

QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------
 Aggregate  (cost=3646.04..3646.05 rows=1 width=0) (actual
time=39.448..39.448 rows=1 loops=1)
   ->  Index Scan using user_messages_user on user_messages
(cost=0.00..3643.53 rows=1000 width=0) (actual time=39.410..39.410
rows=0 loops=1)
         Index Cond: (user_id = 13604)
 Total runtime: 39.648 ms
(4 rows)

So here it's using the right index.

Hmm, but with an estimated cost of 3646 (vs.633 for the max(*) which uses the wrong index). That explains why it's walking backwards through the pkey index, it thinks that it's 8 times cheaper.

It looks like it thinks that because the estimated cost scanning the whole index backwards is 633188 for 1000 rows and you only want one row so that's 1/1000 of that cost.

But why 1000 rows? Actually, it thinks 1000 rows above too. Could it be inadequate stats on the users column? If the users it gathered stats on all have > 1000 rows then it might use the default.

Have a look at most_common_vals,most_common_freqs in pg_stats for tbl=user_messages, att=user perhaps. Then see if an ALTER TABLE SET STATISTICS 100 makes a difference.

Can you trick it with a sub-query (to see the explain)?
SELECT max(id) FROM (SELECT id FROM user_messages WHERE user_id = 13604)
AS foo;

No, I tried that as well; PostgreSQL is clever enough to optimize it
into exactly the same query as the original.

Damn :-)



--
  Richard Huxton
  Archonet Ltd

---------------------------(end of broadcast)---------------------------
TIP 9: In versions below 8.0, the planner will ignore your desire to
      choose an index scan if your joining column's datatypes do not
      match

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Postgresql Jobs]     [Postgresql Admin]     [Postgresql Performance]     [Linux Clusters]     [PHP Home]     [PHP on Windows]     [Kernel Newbies]     [PHP Classes]     [PHP Books]     [PHP Databases]     [Postgresql & PHP]     [Yosemite]
  Powered by Linux