Re: How Postgresql Compares For Query And Load Operations - Mailing list pgsql-general

From Tom Lane
Subject Re: How Postgresql Compares For Query And Load Operations
Date
Msg-id 16772.995035789@sss.pgh.pa.us
Whole thread Raw
In response to How Postgresql Compares For Query And Load Operations  (Mark kirkwood <markir@slingshot.co.nz>)
Responses Re: How Postgresql Compares For Query And Load Operations
Re: How Postgresql Compares For Query And Load Operations
Re: How Postgresql Compares For Query And Load Operations
List pgsql-general
Mark kirkwood <markir@slingshot.co.nz> writes:
> Postgres 7.1.2 executed this query like :

>  Aggregate  (cost=2732703.88..2738731.49 rows=120552 width=20)
>   -> Group  (cost=2732703.88..2735717.69 rows=1205521 width=20)
>       -> Sort  (cost=2732703.88..2732703.88 rows=1205521 width=20)
>          -> Hash Join  (cost=1967.52..2550188.93 rows=1205521 width=20)
>            -> Seq Scan on fact1 f  (cost=0.00..1256604.00 rows=3000000
> width=8)
>            -> Hash  (cost=1957.47..1957.47 rows=4018 width=12)
>              -> Index Scan using dim0_q1 on dim0 d0  (cost=0.00..1957.47
> rows=4018 width=12)

> for an elapsed time of 3m50s

> Wheras Oracle 9.0 used :

>  SELECT STATEMENT Optimizer=CHOOSE (Cost=5810 Card=4020 Bytes =60300)
>      SORT (GROUP BY) (Cost=5810 Card=4020 Bytes=60300)
>        HASH JOIN (Cost=5810 Card=2989644 Bytes=44844660)
>          TABLE ACCESS (FULL) OF 'DIM0' (Cost=4 Card=4020 Bytes= 40200)
>          TABLE ACCESS (FULL) OF 'FACT1' (Cost=5806 Card=2990089
> Bytes=14950445)

> for an elapsed time of 50s.

> It would seem that Oracle's execution plan is more optimal.

Hmm, since I don't know the details of Oracle's plan displays, it's hard
to comment on that --- but it looks to me like the plans are essentially
the same, with the small difference that Postgres chooses to use the
index on dim0 to filter out the dim0 rows that don't meet
    d0.f1 between '2007-07-01' AND '2018-07-01'
before they get loaded into the hashtable, whereas Oracle is just
scanning dim0 by brute force (and presumably evaluating the BETWEEN
clause directly at each row).  Given that that's the much smaller table,
it's unlikely that that makes much difference.  I am assuming that the
different order in which the hash-join's inputs are listed is just an
artifact of the listing format --- surely Oracle is also choosing to
load the dim0 rows into an in-memory hash table and then scan fact1
to probe the hash table, rather than trying to load all of fact1 into
memory.

My guess is that the Oracle plan is misleading where it says "SORT",
and that they are actually doing no such thing as a sort.  Given that
they only expect 4000 distinct rows out of the grouping/aggregation
steps, it'd make more sense to do the group+aggregation in one pass
using another in-memory hash table (indexed by GROUP BY key, with
contents being the count() accumulator).  Currently, Postgres only knows
how to form groups via a true sort and then a "GROUP" pass (works like
the traditional "sort | uniq" Unix filtering method).  But if you
actually want to aggregate the groups, and there aren't too many of
them, then you can form each aggregate in parallel in one unsorted pass
over the input, keeping the aggregate intermediate results in entries in
a hash table.  Hash-based aggregation is on our TODO list, and is
fairly high priority in my eyes (though I doubt it'll be done for 7.2).

If Oracle really is doing a sort, it's hard to see where the speed
difference came from --- unless you have set the tuning parameters such
that Oracle does the sort all-in-memory whereas Postgres doesn't.  Sorts
that have to go to disk are lots slower.

Can anyone who actually knows how to read Oracle plans confirm or deny
these speculations?


> Buld Load times for a 3000000 row (700Mb ) fact table were

> Postgresql    9m30s    (copy)
> Db2        2m15s    (load)
> Oracle        5m    (sqlldr)
> Mysql        2m20s    (load)

Hmm, I couldn't make out from your webpage exactly how you did the
loading, or which steps are included in your timings.  I see that you
used COPY, which is good ... but did you create the indexes before or
after COPY?  What about the constraints?  I also see a CLUSTER script
--- was this used, and if so where is its time counted?

            regards, tom lane

pgsql-general by date:

Previous
From: wsheldah@lexmark.com
Date:
Subject: RE: Outer joins
Next
From: Thomas Lockhart
Date:
Subject: Re: [PATCH] To remove EXTEND INDEX