Thread: select off of a view going slowly

select off of a view going slowly

From
Fran Fabrizio
Date:
I have a view called error_log.  Most selects off of this view will
return 0 rows and in fact almost always, the error_log will be
completely empty.  It's taking almost .2 seconds to run a 'select count
from error_log where site_id=1 and host_id=2'.

Creating an index on a view would seem counterintuitive, but I tried
anyway.  Surprisingly, it did create something (\d error_log_index
showed the index) but a subsequent \d on the error_log view and on the
table it is created from did not show an associated index, and nothing
got faster anyway.

I've included the EXPLAIN results below, I'm not real good at
interpreting them yet, so I'm not real sure what I am looking for.

Any ideas?

Thanks,
Fran

monitoring=# \d error_log
        View "error_log"
 Attribute |  Type   | Modifier
-----------+---------+----------
 count     | integer |
 site_id   | bigint  |
 host_id   | bigint  |
View definition: SELECT count(*) AS count, log.site_id, log.host_id FROM
log WHE
RE (((log.status = 'CRIT'::"varchar") OR (log.status =
'EMERG'::"varchar")) AND
(log.tstamp > (now() - '1 00:00'::"interval"))) GROUP BY log.site_id,
log.host_i
d;

monitoring=# explain select count from error_log where site_id=24 and
host_id=67
;
NOTICE:  QUERY PLAN:

Aggregate  (cost=18398.08..18398.09 rows=0 width=16)
  ->  Group  (cost=18398.08..18398.09 rows=1 width=16)
        ->  Sort  (cost=18398.08..18398.08 rows=1 width=16)
              ->  Seq Scan on log  (cost=0.00..18398.07 rows=1 width=16)

EXPLAIN
monitoring=# select count from error_log where site_id=24 and
host_id=67;
 count
-------
(0 rows)

monitoring=#

010507.11:03:11.320  [6801] StartTransactionCommand
010507.11:03:11.321  [6801] query: select count from error_log where
site_id=24 and host_id=67;
010507.11:03:11.321  [6801] ProcessQuery
010507.11:03:12.495  [6801] CommitTransactionCommand




Re: select off of a view going slowly

From
Tom Lane
Date:
Fran Fabrizio <ffabrizio@exchange.webmd.net> writes:
> Creating an index on a view would seem counterintuitive, but I tried
> anyway.

The system should not have let you do this (and 7.1 doesn't).

> View definition: SELECT count(*) AS count, log.site_id, log.host_id FROM
> log WHERE (((log.status = 'CRIT'::"varchar") OR (log.status =
> 'EMERG'::"varchar")) AND
> (log.tstamp > (now() - '1 00:00'::"interval"))) GROUP BY log.site_id,
> log.host_id;

Hm.  An index on log.tstamp might help.

BTW, I would recommend an update to 7.1 before you go much further.
Older releases have lots of problems with grouped views.

            regards, tom lane

Re: select off of a view going slowly

From
Fran Fabrizio
Date:
Hello all,

I've finished upgrading to 7.1 and I'm still having trouble getting this view
to run respectably.

Does a view run its query every time I select from the view?  I had been
assuming that the view recreates itself when I modify the table to which the
view is attached, but Tom mentioned that adding an index on tstamp (which i
did) might help, which would imply that every time I select from the view it
is querying the original table (since tstamp lives there but not in the
view).  I did add the index (and one on status) with no effects.

It's still taking wayyyy long to run the select against this view (see stats
below).  I've included some select queries and their stats, a \d of the
error_log view, a \d of the log table from which it is derived, and an
EXPLAIN on the typical-case query.

I'm not real familiar with views so maybe I am not using them in the proper
way.Any pointers at all would be greatly appreciated, as this seems to be the
last hurdle I need to get over before I have a usable application.  Thank you
very much!  (Also, I promise that once I get this application working and can
get my boss off my back, I'll take some time and learn about views, and
relational databases in general, more deeply.   Then maybe I can help out
around here some more! =)

Thanks,
Fran

monitoring=# select * from error_log;
 count | site_id | host_id
-------+---------+---------
     8 |      34 |      88
     8 |      34 |     110
(2 rows)

The query statistics:
2001-05-07 16:31:57 DEBUG:  query: select * from error_log;
2001-05-07 16:31:57 DEBUG:  ProcessQuery
2001-05-07 16:32:02 DEBUG:  CommitTransactionCommand
QUERY STATISTICS
! system usage stats:
!       4.428527 elapsed 3.720000 user 0.710000 system sec

monitoring=# select * from error_log where site_id=34 and host_id=88;
 count | site_id | host_id
-------+---------+---------
     8 |      34 |      88
(1 row)

2001-05-07 16:32:46 DEBUG:  query: select * from error_log where site_id=34
and host_id=88;
2001-05-07 16:32:46 DEBUG:  ProcessQuery
2001-05-07 16:32:48 DEBUG:  CommitTransactionCommand
QUERY STATISTICS
! system usage stats:
!       2.152403 elapsed 1.530000 user 0.620000 system sec

monitoring=# \d error_log
        View "error_log"
 Attribute |  Type   | Modifier
-----------+---------+----------
 count     | integer |
 site_id   | bigint  |
 host_id   | bigint  |
View definition: SELECT count(*) AS count, log.site_id, log.host_id FROM log
WHE
RE (((log.status = 'CRIT'::"varchar") OR (log.status = 'EMERG'::"varchar"))
AND
(log.tstamp > (now() - '1 day'::"interval"))) GROUP BY log.site_id,
log.host_id;

monitoring=# \d log
                    Table "log"
  Attribute   |           Type           | Modifier
--------------+--------------------------+----------
 site_id      | bigint                   |
 host_id      | bigint                   |
 fqdn         | character varying        | not null
 site         | character varying        | not null
 region       | character varying        | not null
 hostname     | character varying        | not null
 product      | character varying        | not null
 class        | character varying        | not null
 subclass     | character varying        | not null
 status       | character varying        | not null
 msg          | character varying        | not null
 remote_stamp | timestamp with time zone | not null
 tstamp       | timestamp with time zone | not null
Indices: log_hostid_index,
         log_siteid_hostid_index,
         log_siteid_index,
         log_status_index,
         log_tstamp_index

monitoring=# explain select * from error_log where site_id=34 and host_id=88;

NOTICE:  QUERY PLAN:

Subquery Scan error_log  (cost=33145.20..33145.21 rows=1 width=16)
  ->  Aggregate  (cost=33145.20..33145.21 rows=1 width=16)
        ->  Group  (cost=33145.20..33145.21 rows=1 width=16)
              ->  Sort  (cost=33145.20..33145.20 rows=1 width=16)
                    ->  Seq Scan on log  (cost=0.00..33145.19 rows=1
width=16)

EXPLAIN
monitoring=#



Re: select off of a view going slowly

From
Tom Lane
Date:
Fran Fabrizio <ffabrizio@exchange.webmd.net> writes:
> Does a view run its query every time I select from the view?

Yes.  That's sort of the point.

> View definition: SELECT count(*) AS count, log.site_id, log.host_id FROM log
> WHERE (((log.status = 'CRIT'::"varchar") OR (log.status = 'EMERG'::"varchar"))
> AND (log.tstamp > (now() - '1 day'::"interval"))) GROUP BY log.site_id,
> log.host_id;

> monitoring=# \d log
>                     Table "log"
>   Attribute   |           Type           | Modifier
> --------------+--------------------------+----------
>  site_id      | bigint                   |
>  host_id      | bigint                   |
>  fqdn         | character varying        | not null
>  site         | character varying        | not null
>  region       | character varying        | not null
>  hostname     | character varying        | not null
>  product      | character varying        | not null
>  class        | character varying        | not null
>  subclass     | character varying        | not null
>  status       | character varying        | not null
>  msg          | character varying        | not null
>  remote_stamp | timestamp with time zone | not null
>  tstamp       | timestamp with time zone | not null
> Indices: log_hostid_index,
>          log_siteid_hostid_index,
>          log_siteid_index,
>          log_status_index,
>          log_tstamp_index

> monitoring=# explain select * from error_log where site_id=34 and host_id=88;

> NOTICE:  QUERY PLAN:

> Subquery Scan error_log  (cost=33145.20..33145.21 rows=1 width=16)
>   ->  Aggregate  (cost=33145.20..33145.21 rows=1 width=16)
>         ->  Group  (cost=33145.20..33145.21 rows=1 width=16)
>               ->  Sort  (cost=33145.20..33145.20 rows=1 width=16)
>                     ->  Seq Scan on log  (cost=0.00..33145.19 rows=1
> width=16)

You need to get rid of that bottom seqscan.  Unfortunately, you're
running into a couple of deficiencies that prevent Postgres from
choosing either of the reasonable indexes (siteid_hostid or tstamp).
The one that's easiest to get around is siteid/hostid: try

explain select * from error_log where site_id=34::int8 and host_id=88::int8;

As you've written it, the WHERE clause contains int8 vs. int4
comparisons, which the planner is not smart about turning into
operations that have something to do with an int8 index.  So
you need to make the comparisons look like int8 vs. int8.
(Alternatively: do the siteid and hostid really need to be bigint?
Could you get by with int4, at least for a release or two more?)

The other possibility is to use the tstamp index with the
log.tstamp > (now() - '1 day'::"interval") clause.  But this is not
considered indexable because "now() - '1 day'::interval" is not known
to reduce to a constant.  It's possible to hack up your own function
to allow this to be treated as a constant, see previous discussions eg
http://www.geocrawler.com/archives/3/10/2000/9/0/4324734/

We have plans to address both of these issues in future releases...

            regards, tom lane

Re: select off of a view going slowly

From
Fran Fabrizio
Date:
Tom, your suggestions have had an interesting and unexpected result......remember
the original query 'select count from error_log where site_id=39 and
host_id=99'....you suggested that I change this to add the ::int8 and enable use of
the index.  I did this and the EXPLAIN results definitely show the difference.
However, with the new query, depending on the values of site_id and host_id,
execution time varies from .002 to 1.617 seconds!

Very odd, no?  I wonder why the drastic (80000% variation!) difference in execution
times?  I've vacuum'ed and vacuum anaylzed the table, too.

EXPLAIN
monitoring=# explain select count from error_log where site_id=39::int8 and
host_id=99::int8;
NOTICE:  QUERY PLAN:

Subquery Scan error_log  (cost=0.00..4.90 rows=1 width=16)
  ->  Aggregate  (cost=0.00..4.90 rows=1 width=16)
        ->  Group  (cost=0.00..4.90 rows=1 width=16)
              ->  Index Scan using log_siteid_hostid_index on log  (cost=0.00..4.90
rows=1 width=16)

monitoring=# explain select count from error_log where site_id=14::int8 and
host_id=41::int8;
NOTICE:  QUERY PLAN:

Subquery Scan error_log  (cost=0.00..4.90 rows=1 width=16)
  ->  Aggregate  (cost=0.00..4.90 rows=1 width=16)
        ->  Group  (cost=0.00..4.90 rows=1 width=16)
              ->  Index Scan using log_siteid_hostid_index on log  (cost=0.00..4.90
rows=1 width=16)

EXPLAIN
monitoring=#

2001-05-08 14:21:17 DEBUG:  query: select count from error_log where
site_id=39::int8 and host_id=99::int8;
QUERY STATISTICS
! system usage stats:
!       0.002321 elapsed 0.000000 user 0.000000 system sec

2001-05-08 14:21:21 DEBUG:  query:  select count from error_log where
site_id=14::int8 and host_id=41::int8;
QUERY STATISTICS
! system usage stats:
!       1.617670 elapsed 0.810000 user 0.810000 system sec



Re: select off of a view going slowly

From
Tom Lane
Date:
Fran Fabrizio <ffabrizio@exchange.webmd.net> writes:
> However, with the new query, depending on the values of site_id and host_id,
> execution time varies from .002 to 1.617 seconds!

Does one site and/or host have many more table entries than the other?

            regards, tom lane

Re: select off of a view going slowly

From
Fran Fabrizio
Date:
Tom Lane wrote:

> Fran Fabrizio <ffabrizio@exchange.webmd.net> writes:
> > However, with the new query, depending on the values of site_id and host_id,
> > execution time varies from .002 to 1.617 seconds!
>
> Does one site and/or host have many more table entries than the other?

I just tried clustering the table around that siteid_hostid_index and it did
reduce the number of blocks read from 15000 to 2200 for the query.  However,
still running pretty slow (.9 second).  I'm beginning to think I need something
more robust than a view.  Perhaps I need to build an error_log table that gets
updated via trigger upon insert into log.  We shall see.

Thanks,
Fran