Performance problems, bad estimates and plan - Mailing list pgsql-performance

From Allan Wang
Subject Performance problems, bad estimates and plan
Date
Msg-id 1118243044.3454.3.camel@localhost
Whole thread Raw
Responses Re: Performance problems, bad estimates and plan
List pgsql-performance
It seems that Postgres is estimating that all rows in a 50k row table
will be returned, but only one should match. The query runs slow because
of the seqscan. When I set enable_seqscan to off, then it does an index
scan and it runs quickly.

I've set the statistics target on the index to 100 and 1000, and they
don't make a difference in the plan. I've also ran VACUUM ANALYZE right
before the query.

Here is my query, output of EXPLAIN ANALYZE, and my tables:
I'm not sure how wrapping will make this look, so I've put it into a
pastebin also, if it makes it easier to read:
http://rafb.net/paste/results/RqeyX523.nln.html

talluria=# explain analyze SELECT t.*, p.name AS owner, c.name FROM
tiles AS t LEFT JOIN cities AS c USING (cityid) LEFT JOIN players p
USING (playerid) WHERE box(t.coord, t.coord) ~= box(point (4,3), point
(4,3));
                                                                  QUERY PLAN

-----------------------------------------------------------------------------------------------------------------------------------------------
 Merge Right Join  (cost=119.07..122.13 rows=52 width=55) (actual time=232.777..232.780 rows=1 loops=1)
   Merge Cond: ("outer".playerid = "inner".playerid)
   ->  Index Scan using users_pkey on players p  (cost=0.00..4138.82 rows=56200 width=8) (actual time=0.017..122.409
rows=56200loops=1) 
   ->  Sort  (cost=119.07..119.20 rows=52 width=55) (actual time=0.070..0.072 rows=1 loops=1)
         Sort Key: c.playerid
         ->  Hash Left Join  (cost=1.03..117.59 rows=52 width=55) (actual time=0.045..0.059 rows=1 loops=1)
               Hash Cond: ("outer".cityid = "inner".cityid)
               ->  Index Scan using tiles_coord_key on tiles t  (cost=0.00..116.29 rows=52 width=37) (actual
time=0.014..0.026rows=1 loops=1) 
                     Index Cond: (box(coord, coord) ~= '(4,3),(4,3)'::box)
               ->  Hash  (cost=1.02..1.02 rows=2 width=22) (actual time=0.017..0.017 rows=0 loops=1)
                     ->  Seq Scan on cities c  (cost=0.00..1.02 rows=2 width=22) (actual time=0.008..0.012 rows=2
loops=1)
 Total runtime: 232.893 ms
(12 rows)

talluria=# set enable_seqscan = false;
SET
talluria=# explain analyze SELECT t.*, p.name AS owner, c.name FROM tiles AS t LEFT JOIN cities AS c USING (cityid)
LEFTJOIN players p USING (playerid) WHERE box(t.coord, t.coord) ~= box(point (4,3), point (4,3)); 
                                                                     QUERY PLAN

-----------------------------------------------------------------------------------------------------------------------------------------------------
 Merge Left Join  (cost=121.07..124.14 rows=52 width=55) (actual time=0.102..0.105 rows=1 loops=1)
   Merge Cond: ("outer".playerid = "inner".playerid)
   ->  Sort  (cost=121.07..121.20 rows=52 width=55) (actual time=0.076..0.077 rows=1 loops=1)
         Sort Key: c.playerid
         ->  Hash Left Join  (cost=3.03..119.59 rows=52 width=55) (actual time=0.053..0.066 rows=1 loops=1)
               Hash Cond: ("outer".cityid = "inner".cityid)
               ->  Index Scan using tiles_coord_key on tiles t  (cost=0.00..116.29 rows=52 width=37) (actual
time=0.014..0.026rows=1 loops=1) 
                     Index Cond: (box(coord, coord) ~= '(4,3),(4,3)'::box)
               ->  Hash  (cost=3.02..3.02 rows=2 width=22) (actual time=0.026..0.026 rows=0 loops=1)
                     ->  Index Scan using cities_userid_key on cities c  (cost=0.00..3.02 rows=2 width=22) (actual
time=0.016..0.021rows=2 loops=1) 
   ->  Index Scan using users_pkey on players p  (cost=0.00..4138.82 rows=56200 width=8) (actual time=0.012..0.012
rows=1loops=1) 
 Total runtime: 0.200 ms
(12 rows)

talluria=# \d tiles
                                       Table "public.tiles"
 Column |       Type        |                              Modifiers
--------+-------------------+----------------------------------------------------------------------
 tileid | integer           | not null default nextval('tiles_tileid_seq'::text)
 mapid  | integer           | not null default 1
 tile   | character varying | not null default 'field'::character varying
 coord  | point             | not null default point((0)::double precision, (0)::double precision)
 cityid | integer           |
Indexes:
    "times_pkey" PRIMARY KEY, btree (tileid) CLUSTER
    "tiles_cityid_key" btree (cityid)
    "tiles_coord_key" rtree (box(coord, coord))
Foreign-key constraints:
    "tiles_cityid_fkey" FOREIGN KEY (cityid) REFERENCES cities(cityid) ON UPDATE CASCADE ON DELETE SET NULL

talluria=# \d cities
                                   Table "public.cities"
   Column    |         Type          |                      Modifiers
-------------+-----------------------+-----------------------------------------------------
 cityid      | integer               | not null default nextval('cities_cityid_seq'::text)
 playerid    | integer               | not null default 0
 bordercolor | character(6)          | not null default '0000ff'::bpchar
 citystatus  | smallint              | not null default 0
 name        | character varying(30) | not null
Indexes:
    "cities_pkey" PRIMARY KEY, btree (cityid)
    "cities_cityname_uikey" UNIQUE, btree (lower(name::text))
    "cities_userid_key" btree (playerid)
Foreign-key constraints:
    "cities_userid_fkey" FOREIGN KEY (playerid) REFERENCES players(playerid) ON UPDATE CASCADE ON DELETE CASCADE

talluria=# \d players
                                             Table "public.players"
     Column      |          Type          |                              Modifiers
-----------------+------------------------+----------------------------------------------------------------------
 playerid        | integer                | not null default nextval('players_playerid_seq'::text)
 username        | character varying(30)  | not null default ''::character varying
 md5password     | character(32)          | not null default (''::bpchar)::character(1)
 name            | character varying(100) | not null default ''::character varying
 email           | character varying(50)  | not null default ''::character varying
(snipped a few irrelavent columns)
Indexes:
    "users_pkey" PRIMARY KEY, btree (playerid)
    "players_username_key" UNIQUE, btree (username, md5password)
    "users_username_lkey" UNIQUE, btree (lower(username::text))
    "users_coord_key" rtree (box(coord, coord))
Foreign-key constraints:
    "players_stylesheet_fkey" FOREIGN KEY (stylesheet) REFERENCES stylesheets(stylesheetid) ON UPDATE CASCADE ON DELETE
SETDEFAULT 
    "users_arm" FOREIGN KEY (arm) REFERENCES items(itemid) ON UPDATE CASCADE ON DELETE SET NULL
    "users_activefight_pkey" FOREIGN KEY (activefight) REFERENCES monsters(monsterid) ON UPDATE CASCADE ON DELETE SET
NULL
    "players_map_fkey" FOREIGN KEY (map) REFERENCES maps(mapid) ON UPDATE CASCADE ON DELETE SET DEFAULT
    "users_belt" FOREIGN KEY (belt) REFERENCES items(itemid) ON UPDATE CASCADE ON DELETE SET NULL
    "users_body" FOREIGN KEY (body) REFERENCES items(itemid) ON UPDATE CASCADE ON DELETE SET NULL
    "users_head" FOREIGN KEY (head) REFERENCES items(itemid) ON UPDATE CASCADE ON DELETE SET NULL
    "users_lefthand" FOREIGN KEY (lefthand) REFERENCES items(itemid) ON UPDATE CASCADE ON DELETE SET NULL
    "users_leg" FOREIGN KEY (leg) REFERENCES items(itemid) ON UPDATE CASCADE ON DELETE SET NULL
    "users_righthand" FOREIGN KEY (righthand) REFERENCES items(itemid) ON UPDATE CASCADE ON DELETE SET NULL

Thanks in advance for any help,
Allan Wang


pgsql-performance by date:

Previous
From: George Essig
Date:
Subject: Re: SELECT DISTINCT Performance Issue
Next
From: Tom Lane
Date:
Subject: Re: full outer performance problem