Unused table of view - Mailing list pgsql-performance

From Laurent Martelli
Subject Unused table of view
Date
Msg-id 87y8n2t6jd.fsf@stan.aopsys.com
Whole thread Raw
Responses Re: Unused table of view
List pgsql-performance
Hello,

I'm using postgresql 7.4.2, and I have this view:
slooze=# \d userpictures2
     Vue «public.userpictures2»
   Colonne   |           Type           | Modificateurs
-------------+--------------------------+---------------
 pictureid   | integer                  |
 rollid      | character varying(64)    |
 frameid     | character varying(64)    |
 description | character varying(255)   |
 filename    | character varying(255)   |
 owner       | integer                  |
 entrydate   | timestamp with time zone |
 date        | timestamp with time zone |
 nbclick     | integer                  |
 nbrates     | integer                  |
 maxrate     | smallint                 |
 minrate     | smallint                 |
 averagerate | real                     |
 sumrates    | integer                  |
 userid      | integer                  |
Définition de la vue
 SELECT DISTINCT ON (permissions.pictureid, userid) pictures.pictureid, rollid, frameid, description, filename,
"owner",entrydate, date, nbclick, nbrates, maxrate, minrate, averagerate, sumrates, userid 
   FROM permissions
   JOIN groupsdef USING (groupid)
   JOIN pictures USING (pictureid)
  WHERE groupsdef.groupid = permissions.groupid
  ORDER BY permissions.pictureid, userid;


Now consider this query:

SELECT count(*) FROM userpictures JOIN topicscontent using(PictureID) WHERE TopicID=137 and UserID=2;

The pictures table is scanned, but it's not needed. (see plan at the end).

I believe it's not need because my tables are as follow:

CREATE TABLE pictures (
    PictureID serial PRIMARY KEY,
    RollID character varying(64) NOT NULL REFERENCES rolls,
    FrameID character varying(64) NOT NULL,
    Description character varying(255),
    Filename character varying(255),
    Owner integer NOT NULL REFERENCES users,
    EntryDate datetime DEFAULT now(),
    Date datetime,
    NbClick integer DEFAULT 0,
    NbRates integer DEFAULT 0,
    MaxRate int2,
    MinRate int2,
    AverageRate float4 DEFAULT 5,
    SumRates integer DEFAULT 0);

CREATE TABLE permissions (
    GroupID integer NOT NULL REFERENCES groups ON DELETE cascade,
    PictureID integer NOT NULL REFERENCES pictures ON DELETE cascade,
    UNIQUE (GroupID, PictureID));

CREATE TABLE groupsdef (
    UserID integer REFERENCES users,
    GroupID integer REFERENCES groups,
    PRIMARY KEY (UserID,GroupID));

CREATE TABLE topicscontent (
    TopicID integer REFERENCES topics ON DELETE cascade,
    PictureID integer REFERENCES pictures ON DELETE cascade,
    Direct boolean NOT NULL,
    PRIMARY KEY (TopicID,PictureID) );

So obviously, the join on pictures is not adding any rows, since
permissions.PictureID references pictures.PictureID and
pictures.PictureID is the primary key.

I can workaround with a second view:

slooze=# \d userpictures2
     Vue «public.userpictures2»
  Colonne  |  Type   | Modificateurs
-----------+---------+---------------
 pictureid | integer |
 userid    | integer |
Définition de la vue
 SELECT DISTINCT pictureid, userid
   FROM permissions
   JOIN groupsdef USING (groupid)
  WHERE groupsdef.groupid = permissions.groupid
  ORDER BY pictureid, userid;

But it would be better if Postgresql could figure it out itself. Is
there a way to currently avoid the 2nd view ?

QUERY PLAN for SELECT count(*) FROM userpictures JOIN topicscontent using(PictureID) WHERE TopicID=137 and UserID=2;
--------------------------------------------------------------------------------------------------------------------
 Aggregate  (cost=1195.15..1195.15 rows=1 width=0) (actual time=89.252..89.253 rows=1 loops=1)
   ->  Merge Join  (cost=1096.05..1194.98 rows=66 width=0) (actual time=84.574..89.202 rows=8 loops=1)
         Merge Cond: ("outer".pictureid = "inner".pictureid)
         ->  Subquery Scan userpictures  (cost=995.78..1081.47 rows=4897 width=4) (actual time=84.386..88.530 rows=841
loops=1)
               ->  Unique  (cost=995.78..1032.50 rows=4897 width=105) (actual time=84.377..87.803 rows=841 loops=1)
                     ->  Sort  (cost=995.78..1008.02 rows=4897 width=105) (actual time=84.369..84.786 rows=1433
loops=1)
                           Sort Key: permissions.pictureid, groupsdef.userid
                           ->  Hash Join  (cost=371.82..695.65 rows=4897 width=105) (actual time=23.328..56.498
rows=5076loops=1) 
                                 Hash Cond: ("outer".pictureid = "inner".pictureid)
                                 ->  Index Scan using pictures_pkey on pictures  (cost=0.00..164.87 rows=2933 width=97)
(actualtime=0.015..4.591 rows=2933 loops=1) 
                                 ->  Hash  (cost=359.58..359.58 rows=4897 width=8) (actual time=23.191..23.191 rows=0
loops=1)
                                       ->  Merge Join  (cost=10.16..359.58 rows=4897 width=8) (actual
time=0.110..19.365rows=5076 loops=1) 
                                             Merge Cond: ("outer".groupid = "inner".groupid)
                                             ->  Sort  (cost=10.16..10.19 rows=12 width=8) (actual time=0.080..0.088
rows=11loops=1) 
                                                   Sort Key: groupsdef.groupid
                                                   ->  Index Scan using groupsdef_userid_key on groupsdef
(cost=0.00..9.94rows=12 width=8) (actual time=0.038..0.056 rows=11 loops=1) 
                                                         Index Cond: (userid = 2)
                                             ->  Index Scan using permissions_groupid_key on permissions
(cost=0.00..279.63rows=8305 width=8) (actual time=0.015..9.801 rows=7633 loops=1) 
         ->  Sort  (cost=100.28..100.37 rows=38 width=4) (actual time=0.114..0.118 rows=8 loops=1)
               Sort Key: topicscontent.pictureid
               ->  Index Scan using topicscontent_topicid on topicscontent  (cost=0.00..99.28 rows=38 width=4) (actual
time=0.052..0.072rows=8 loops=1) 
                     Index Cond: (topicid = 137)
 Total runtime: 91.096 ms


QUERY PLAN for SELECT count(*) FROM userpictures JOIN topicscontent using(PictureID) WHERE TopicID=137 and UserID=2;
--------------------------------------------------------------------------------------------------------------------
 Aggregate  (cost=859.09..859.09 rows=1 width=4) (actual time=30.488..30.489 rows=1 loops=1)
   ->  Merge Join  (cost=759.99..858.92 rows=66 width=4) (actual time=27.845..30.466 rows=8 loops=1)
         Merge Cond: ("outer".pictureid = "inner".pictureid)
         ->  Subquery Scan userpictures2  (cost=659.71..745.41 rows=4897 width=4) (actual time=27.707..29.853 rows=841
loops=1)
               ->  Unique  (cost=659.71..696.44 rows=4897 width=8) (actual time=27.701..29.121 rows=841 loops=1)
                     ->  Sort  (cost=659.71..671.95 rows=4897 width=8) (actual time=27.696..28.153 rows=1433 loops=1)
                           Sort Key: permissions.pictureid, groupsdef.userid
                           ->  Merge Join  (cost=10.16..359.58 rows=4897 width=8) (actual time=0.101..20.682 rows=5076
loops=1)
                                 Merge Cond: ("outer".groupid = "inner".groupid)
                                 ->  Sort  (cost=10.16..10.19 rows=12 width=8) (actual time=0.074..0.078 rows=11
loops=1)
                                       Sort Key: groupsdef.groupid
                                       ->  Index Scan using groupsdef_userid_key on groupsdef  (cost=0.00..9.94 rows=12
width=8)(actual time=0.035..0.055 rows=11 loops=1) 
                                             Index Cond: (userid = 2)
                                 ->  Index Scan using permissions_groupid_key on permissions  (cost=0.00..279.63
rows=8305width=8) (actual time=0.014..10.093 rows=7633 loops=1) 
         ->  Sort  (cost=100.28..100.37 rows=38 width=4) (actual time=0.091..0.094 rows=8 loops=1)
               Sort Key: topicscontent.pictureid
               ->  Index Scan using topicscontent_topicid on topicscontent  (cost=0.00..99.28 rows=38 width=4) (actual
time=0.039..0.057rows=8 loops=1) 
                     Index Cond: (topicid = 137)
 Total runtime: 31.376 ms

--
Laurent Martelli
laurent@aopsys.com                                Java Aspect Components
http://www.aopsys.com/                          http://jac.objectweb.org


pgsql-performance by date:

Previous
From: Tom Lane
Date:
Subject: Re: postgres performance: comparing 2 data centers
Next
From: Tom Lane
Date:
Subject: Re: Unused table of view