X-Original-To: pgsql-performance-postgresql.org@localhost.postgresql.org Received: from localhost (av.hub.org [200.46.204.144]) by postgresql.org (Postfix) with ESMTP id 52CAE9DCA41 for ; Wed, 8 Mar 2006 13:15:18 -0400 (AST) Received: from postgresql.org ([200.46.204.71]) by localhost (av.hub.org [200.46.204.144]) (amavisd-new, port 10024) with ESMTP id 40200-01 for ; Wed, 8 Mar 2006 13:15:16 -0400 (AST) Received: from svr4.postgresql.org (svr4.postgresql.org [66.98.251.159]) by postgresql.org (Postfix) with ESMTP id 20E9E9DCA1C for ; Wed, 8 Mar 2006 13:15:15 -0400 (AST) Received: from ylpvm43.prodigy.net (ylpvm43-ext.prodigy.net [207.115.57.74]) by svr4.postgresql.org (Postfix) with ESMTP id 97FAA5AF18F for ; Wed, 8 Mar 2006 17:15:12 +0000 (GMT) Received: from pimout1-ext.prodigy.net (pimout1-int.prodigy.net [207.115.5.65]) by ylpvm43.prodigy.net (8.12.10 outbound/8.12.10) with ESMTP id k28HFDBd013555 for ; Wed, 8 Mar 2006 12:15:13 -0500 X-ORBL: [68.92.113.60] Received: from homer.d-oh.org (adsl-68-92-113-60.dsl.okcyok.swbell.net [68.92.113.60]) by pimout1-ext.prodigy.net (8.13.4 outbound domainkey aix/8.13.4) with SMTP id k28HF9e2097868 for ; Wed, 8 Mar 2006 12:15:09 -0500 Received: (qmail 2881 invoked by uid 1013); 8 Mar 2006 17:15:03 -0000 Received: from alex@innovacomputing.com by homer by uid 64011 with qmail-scanner-1.20 (clamscan: 0.65. hbedv: 6.22.0.1/6.22.0.50. Clear:RC:1(192.168.0.100):. Processed in 2.217185 secs); 08 Mar 2006 17:15:03 -0000 Received: from unknown (HELO ?192.168.0.100?) (192.168.0.100) by homer.int.d-oh.org with SMTP; 8 Mar 2006 17:15:00 -0000 Message-ID: <440F1115.4020400@innovacomputing.com> Date: Wed, 08 Mar 2006 11:15:01 -0600 From: Alex Adriaanse User-Agent: Thunderbird 1.5 (Windows/20051201) MIME-Version: 1.0 To: Greg Stark Cc: pgsql-performance@postgresql.org Subject: Re: Bad row estimates References: <4408E91C.90104@innovacomputing.com> <87wtfasng0.fsf@stark.xeocode.com> <14850.1141488599@sss.pgh.pa.us> <87fylyrsfy.fsf@stark.xeocode.com> In-Reply-To: <87fylyrsfy.fsf@stark.xeocode.com> Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit X-Virus-Scanned: by amavisd-new at hub.org X-Spam-Status: No, score=0.12 required=5 tests=[AWL=0.120] X-Spam-Score: 0.12 X-Spam-Level: X-Archive-Number: 200603/86 X-Sequence-Number: 17523 Thank you all for your valuable input. I have tried creating a partial index, a GIST index, and a GIST + partial index, as suggested, but it does not seem to make a significant difference. For instance: CREATE INDEX test_table_1_interval_idx ON test_table_1 USING GIST (box(point(start_ts::abstime::integer, start_ts::abstime::integer), point(end_ts::abstime::integer, end_ts::abstime::integer))) WHERE id = g_id; ANALYZE test_table_1; EXPLAIN ANALYZE SELECT count(*) FROM test_table_1 INNER JOIN test_table_2 ON (test_table_2.s_id=13300613 AND test_table_1.id = test_table_2.n_id) WHERE box(point(start_ts::abstime::integer, start_ts::abstime::integer), point(end_ts::abstime::integer, end_ts::abstime::integer)) ~ box(point(now()::abstime::integer,now()::abstime::integer),point(now()::abstime::integer,now()::abstime::integer)) AND test_table_1.id = test_table_1.g_id; QUERY PLAN ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Aggregate (cost=15.09..15.10 rows=1 width=0) (actual time=69.771..69.772 rows=1 loops=1) -> Nested Loop (cost=9.06..15.08 rows=1 width=0) (actual time=69.752..69.752 rows=0 loops=1) -> Index Scan using test_table_1_interval_idx on test_table_1 (cost=0.07..4.07 rows=1 width=22) (actual time=2.930..3.607 rows=135 loops=1) Index Cond: (box(point((((start_ts)::abstime)::integer)::double precision, (((start_ts)::abstime)::integer)::double precision), point((((end_ts)::abstime)::integer)::double precision, (((end_ts)::abstime)::integer)::double precision)) ~ box(point((((now())::abstime)::integer)::double precision, (((now())::abstime)::integer)::double precision), point((((now())::abstime)::integer)::double precision, (((now())::abstime)::integer)::double precision))) -> Bitmap Heap Scan on test_table_2 (cost=8.99..11.00 rows=1 width=12) (actual time=0.486..0.486 rows=0 loops=135) Recheck Cond: ((test_table_2.s_id = 13300613::numeric) AND ("outer".id = test_table_2.n_id)) -> BitmapAnd (cost=8.99..8.99 rows=1 width=0) (actual time=0.485..0.485 rows=0 loops=135) -> Bitmap Index Scan on test_table_2_s_id (cost=0.00..2.17 rows=48 width=0) (actual time=0.015..0.015 rows=1 loops=135) Index Cond: (s_id = 13300613::numeric) -> Bitmap Index Scan on test_table_2_n_id (cost=0.00..6.57 rows=735 width=0) (actual time=0.467..0.467 rows=815 loops=135) Index Cond: ("outer".id = test_table_2.n_id) Total runtime: 69.961 ms (Note: without the GIST index the query currently runs in about 65ms) Its row estimates are still way off. As a matter of fact, it almost seems as if the index doesn't affect row estimates at all. What would you guys suggest? Thanks, Alex Greg Stark wrote: > You could actually take short cuts using expression indexes to do this. If it > works out well then you might want to implement a real data type to avoid the > overhead of the SQL conversion functions. > > Here's an example. If I were to do this for real I would look for a better > datatype than the box datatype and I would wrap the whole conversion in an SQL > function. But this will serve to demonstrate: > > stark=> create table interval_test (start_ts timestamp with time zone, end_ts timestamp with time zone); > CREATE TABLE > > stark=> create index interval_idx on interval_test using gist (box(point(start_ts::abstime::integer, end_ts::abstime::integer) , point(start_ts::abstime::integer, end_ts::abstime::integer))); > CREATE INDEX > > stark=> explain select * from interval_test where box(point(now()::abstime::integer,now()::abstime::integer),point(now()::abstime::integer,now()::abstime::integer)) ~ box(point(start_ts::abstime::integer, end_ts::abstime::integer) , point(start_ts::abstime::integer, end_ts::abstime::integer)); > QUERY PLAN > ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- > Index Scan using interval_idx on interval_test (cost=0.07..8.36 rows=2 width=16) > Index Cond: (box(point((((now())::abstime)::integer)::double precision, (((now())::abstime)::integer)::double precision), point((((now())::abstime)::integer)::double precision, (((now())::abstime)::integer)::double precision)) ~ box(point((((start_ts)::abstime)::integer)::double precision, (((end_ts)::abstime)::integer)::double precision), point((((start_ts)::abstime)::integer)::double precision, (((end_ts)::abstime)::integer)::double precision))) > (2 rows) > >