Thread: Join Query Perfomance Issue

Join Query Perfomance Issue

From
Thomas Zaksek
Date:
I have serious performance problems with the following type of queries:
/
/explain analyse SELECT '12.11.2007 18:04:00 UTC' AS zeit,
                       'M' AS datatyp,
                       p.zs_nr AS zs_de,
                   j_ges,
                       de_mw_abh_j_lkw(mw_abh) AS j_lkw,
                       de_mw_abh_v_pkw(mw_abh) AS v_pkw,
                       de_mw_abh_v_lkw(mw_abh) AS v_lkw,
                   de_mw_abh_p_bel(mw_abh) AS p_bel
                   FROM  messpunkt p, messungen_v_dat_2007_11_12 m, de_mw w
                       WHERE  m.ganglinientyp = 'M'
               AND 381 = m.minute_tag
                       AND (p.nr, p.mw_nr) = (m.messpunkt, w.nr);

Explain analze returns

 Nested Loop  (cost=0.00..50389.39 rows=3009 width=10) (actual
time=0.503..320.872 rows=2189 loops=1)
   ->  Nested Loop  (cost=0.00..30668.61 rows=3009 width=8) (actual
time=0.254..94.116 rows=2189 loops=1)
         ->  Index Scan using
messungen_v_dat_2007_11_12_messpunkt_minute_tag_idx on
messungen_v_dat_2007_11_12 m  (cost=0.00..5063.38 rows=3009 width=4)
(actual time=0.131..9.262 rows=2189 loops=1)
               Index Cond: ((ganglinientyp = 'M'::bpchar) AND (381 =
minute_tag))
         ->  Index Scan using messpunkt_nr_idx on messpunkt p
(cost=0.00..8.50 rows=1 width=12) (actual time=0.019..0.023 rows=1
loops=2189)
               Index Cond: (p.nr = m.messpunkt)
   ->  Index Scan using de_nw_nr_idx on de_mw w  (cost=0.00..6.53 rows=1
width=10) (actual time=0.019..0.023 rows=1 loops=2189)
         Index Cond: (p.mw_nr = w.nr)
 Total runtime: 329.134 ms
(9 rows)

Doesnt looks too bad to me, but i'm not that deep into sql query
optimization. However, these type of query is used in a function to
access a normalized, partitioned database, so better performance in this
queries would speed up the whole database system big times.
Any suggestions here would be great. I allready tested some things,
using inner join, rearranging the order of the tables, but but only
minor changes in the runtime, the version above seemed to get us the
best performance.
/

/

Re: Join Query Perfomance Issue

From
"Scott Marlowe"
Date:
On Feb 11, 2008 12:08 PM, Thomas Zaksek <zaksek@ptt.uni-due.de> wrote:
> I have serious performance problems with the following type of queries:
> /
> /explain analyse SELECT '12.11.2007 18:04:00 UTC' AS zeit,
>                        'M' AS datatyp,
>                        p.zs_nr AS zs_de,
>                    j_ges,
>                        de_mw_abh_j_lkw(mw_abh) AS j_lkw,
>                        de_mw_abh_v_pkw(mw_abh) AS v_pkw,
>                        de_mw_abh_v_lkw(mw_abh) AS v_lkw,
>                    de_mw_abh_p_bel(mw_abh) AS p_bel
>                    FROM  messpunkt p, messungen_v_dat_2007_11_12 m, de_mw w
>                        WHERE  m.ganglinientyp = 'M'
>                AND 381 = m.minute_tag
>                        AND (p.nr, p.mw_nr) = (m.messpunkt, w.nr);
>
> Explain analze returns
>
>  Nested Loop  (cost=0.00..50389.39 rows=3009 width=10) (actual
> time=0.503..320.872 rows=2189 loops=1)
>    ->  Nested Loop  (cost=0.00..30668.61 rows=3009 width=8) (actual
> time=0.254..94.116 rows=2189 loops=1)

This nested loop is using us most of your time.  Try increasing
work_mem and see if it chooses a better join plan, and / or turn off
nested loops for a moment and see if that helps.

set enable_nestloop = off

Note that set enable_xxx = off

Is kind of a hammer to the forebrain setting.  It's not subtle, and
the planner can't work around it.  So use them with caution.  That
said, I had one reporting query that simply wouldn't run fast without
turning off nested loops for that one.  But don't turn off nested
queries universally, they are still a good choice for smaller amounts
of data.

Re: Join Query Perfomance Issue

From
"Scott Marlowe"
Date:
Correction:

> turning off nested loops for that one.  But don't turn off nested
> queries universally, they are still a good choice for smaller amounts
> of data.

queries should be loops up there...

Re: Join Query Perfomance Issue

From
Thomas Zaksek
Date:
Scott Marlowe schrieb:
> On Feb 11, 2008 12:08 PM, Thomas Zaksek <zaksek@ptt.uni-due.de> wrote:
>
>> I have serious performance problems with the following type of queries:
>> /
>> /explain analyse SELECT '12.11.2007 18:04:00 UTC' AS zeit,
>>                        'M' AS datatyp,
>>                        p.zs_nr AS zs_de,
>>                    j_ges,
>>                        de_mw_abh_j_lkw(mw_abh) AS j_lkw,
>>                        de_mw_abh_v_pkw(mw_abh) AS v_pkw,
>>                        de_mw_abh_v_lkw(mw_abh) AS v_lkw,
>>                    de_mw_abh_p_bel(mw_abh) AS p_bel
>>                    FROM  messpunkt p, messungen_v_dat_2007_11_12 m, de_mw w
>>                        WHERE  m.ganglinientyp = 'M'
>>                AND 381 = m.minute_tag
>>                        AND (p.nr, p.mw_nr) = (m.messpunkt, w.nr);
>>
>> Explain analze returns
>>
>>  Nested Loop  (cost=0.00..50389.39 rows=3009 width=10) (actual
>> time=0.503..320.872 rows=2189 loops=1)
>>    ->  Nested Loop  (cost=0.00..30668.61 rows=3009 width=8) (actual
>> time=0.254..94.116 rows=2189 loops=1)
>>
>
> This nested loop is using us most of your time.  Try increasing
> work_mem and see if it chooses a better join plan, and / or turn off
> nested loops for a moment and see if that helps.
>
> set enable_nestloop = off
>
> Note that set enable_xxx = off
>
> Is kind of a hammer to the forebrain setting.  It's not subtle, and
> the planner can't work around it.  So use them with caution.  That
> said, I had one reporting query that simply wouldn't run fast without
> turning off nested loops for that one.  But don't turn off nested
> queries universally, they are still a good choice for smaller amounts
> of data.
>
I tried turning off nestloop, but with terrible results:

Hash Join  (cost=208328.61..228555.14 rows=3050 width=10) (actual
time=33421.071..40362.136 rows=2920 loops=1)
   Hash Cond: (w.nr = p.mw_nr)
   ->  Seq Scan on de_mw w  (cost=0.00..14593.79 rows=891479 width=10)
(actual time=0.012..3379.971 rows=891479 loops=1)
   ->  Hash  (cost=208290.49..208290.49 rows=3050 width=8) (actual
time=33420.877..33420.877 rows=2920 loops=1)
         ->  Merge Join  (cost=5303.71..208290.49 rows=3050 width=8)
(actual time=31.550..33407.688 rows=2920 loops=1)
               Merge Cond: (p.nr = m.messpunkt)
               ->  Index Scan using messpunkt_nr_idx on messpunkt p
(cost=0.00..238879.39 rows=6306026 width=12) (actual
time=0.056..17209.317 rows=4339470 loops=1)
               ->  Sort  (cost=5303.71..5311.34 rows=3050 width=4)
(actual time=25.973..36.858 rows=2920 loops=1)
                     Sort Key: m.messpunkt
                     ->  Index Scan using
messungen_v_dat_2007_11_12_messpunkt_minute_tag_idx on
messungen_v_dat_2007_11_12 m  (cost=0.00..5127.20 rows=3050 width=4)
(actual time=0.124..12.822 rows=2920 loops=1)
                           Index Cond: ((ganglinientyp = 'M'::bpchar)
AND (651 = minute_tag))
 Total runtime: 40373.512 ms
(12 rows)
Looks crappy, isn't it?

I also tried to increase work_men, now the config is
work_mem = 4MB
maintenance_work_mem = 128MB,
in regard to performance, it wasnt effective at all.

The postgresql runs  on a HP Server with dual Opteron, 3GB of Ram, what
are good settings here? The database will have to work with tables of
several 10Millions of Lines, but only a few columns each. No more than
maybe ~5 clients accessing the database at the same time.


Re: Join Query Perfomance Issue

From
"Peter Koczan"
Date:
> I have serious performance problems with the following type of queries:
>
> Doesnt looks too bad to me, but i'm not that deep into sql query
> optimization. However, these type of query is used in a function to
> access a normalized, partitioned database, so better performance in this
> queries would speed up the whole database system big times.
> Any suggestions here would be great. I allready tested some things,
> using inner join, rearranging the order of the tables, but but only
> minor changes in the runtime, the version above seemed to get us the
> best performance.

Can you send the table definitions of the tables involved in the
query, including index information? Might be if we look hard enough we
can find something.

Peter

Re: Join Query Perfomance Issue

From
Thomas Zaksek
Date:
 > Can you send the table definitions of the tables involved in the
 > query, including index information? Might be if we look hard enough we
 > can find something.
 >
 > Peter



  Table "messungen_v_dat_2007_11_12"
    Column     |     Type     | Modifiers | Description
---------------+--------------+-----------+-------------
 ganglinientyp | character(1) |           |
 minute_tag    | smallint     |           |
 messpunkt     | integer      |           |
Indexes:
    "messungen_v_dat_2007_11_12_ganglinientyp_key" UNIQUE, btree
(ganglinientyp, minute_tag, messpunkt)
    "messungen_v_dat_2007_11_12_messpunkt_idx" btree (messpunkt)
    "messungen_v_dat_2007_11_12_messpunkt_minute_tag_idx" btree
(ganglinientyp, minute_tag)
Foreign-key constraints:
    "messungen_v_dat_2007_11_12_messpunkt_fkey" FOREIGN KEY (messpunkt)
REFERENCES messpunkt(nr)
Inherits: messungen_v_dat
Has OIDs: no




                             Table "messpunkt"
 Column |  Type   |
Modifiers                        | Description
--------+---------+--------------------------------------------------------+-------------
 nr     | integer | not null default
nextval('messpunkt_nr_seq'::regclass) |
 zs_nr  | integer
|                                                        |
 mw_nr  | integer
|                                                        |
Indexes:
    "messpunkt_pkey" PRIMARY KEY, btree (nr)
    "messpunkt_zs_nr_key" UNIQUE, btree (zs_nr, mw_nr)
    "messpunkt_mw_idx" btree (mw_nr)
    "messpunkt_nr_idx" btree (nr)
    "messpunkt_zs_idx" btree (zs_nr)
Foreign-key constraints:
    "messpunkt_mw_nr_fkey" FOREIGN KEY (mw_nr) REFERENCES de_mw(nr)
    "messpunkt_zs_nr_fkey" FOREIGN KEY (zs_nr) REFERENCES de_zs(zs)
Has OIDs: no




                              Table "de_mw"
 Column |   Type   |                     Modifiers
| Description
--------+----------+----------------------------------------------------+-------------
 nr     | integer  | not null default nextval('de_mw_nr_seq'::regclass) |
 j_ges  | smallint |                                                    |
 mw_abh | integer  |                                                    |
Indexes:
    "de_mw_pkey" PRIMARY KEY, btree (nr)
    "de_mw_j_ges_key" UNIQUE, btree (j_ges, mw_abh)
    "de_nw_nr_idx" btree (nr)
Check constraints:
    "de_mw_check" CHECK (j_ges IS NOT NULL AND (j_ges = 0 AND (mw_abh =
0 OR mw_abh = 255 OR mw_abh IS NULL) OR j_ges > 0 AND j_ges <= 80 AND
mw_abh <> 0))
Has OIDs: no

Re: Join Query Perfomance Issue

From
Thomas Zaksek
Date:
We have tried some recoding now, using a materialized view we could
reduce the query to a join over too tables without any functions inside
the query, for example:

explain analyse SELECT '12.11.2007 18:04:00 UTC' AS zeit,
                       'M' AS ganglinientyp,
                       zs_de,
                   j_ges,
                       j_lkw,
                       v_pkw,
                       v_lkw,
                   p_bel
                   FROM  messungen_v_dat_2007_11_12 m
                       LEFT JOIN messwerte_mv w on w.nr = m.messpunkt
                       WHERE  m.ganglinientyp = 'M'
               AND 992 = m.minute_tag;

Nested Loop Left Join  (cost=0.00..32604.48 rows=3204 width=14) (actual
time=11.991..2223.227 rows=2950 loops=1)
   ->  Index Scan using
messungen_v_dat_2007_11_12_messpunkt_minute_tag_idx on
messungen_v_dat_2007_11_12 m  (cost=0.00..5371.09 rows=3204 width=4)
(actual time=0.152..12.385 rows=2950 loops=1)
         Index Cond: ((ganglinientyp = 'M'::bpchar) AND (992 = minute_tag))
   ->  Index Scan using messwerte_mv_nr_idx on messwerte_mv w
(cost=0.00..8.49 rows=1 width=18) (actual time=0.730..0.734 rows=1
loops=2950)
         Index Cond: (w.nr = m.messpunkt)
 Total runtime: 2234.143 ms
(6 rows)

To me this plan looks very clean and nearly optimal, BUT ~2seconds for
the nested loop can't be that good, isn't it?
The behavior of this query and the database is quite a mystery for me,
yesterday i had it running in about 100ms, today i started testing with
the same query and 2000-3000ms :(

Could this be some kind of a postgresql server/configuration problem?
This queries are very perfomance dependend, they are called a lot of
times in a comlex physical real time simulation of traffic systems.
200ms would be ok here, but >1sec is perhaps not functional.

The old version just used one big (partitioned) table without any joins,
performing this query in 10-300ms, depended on the server load.

Re: Join Query Perfomance Issue

From
Tom Lane
Date:
Thomas Zaksek <zaksek@ptt.uni-due.de> writes:
> Nested Loop Left Join  (cost=0.00..32604.48 rows=3204 width=14) (actual
> time=11.991..2223.227 rows=2950 loops=1)
>    ->  Index Scan using
> messungen_v_dat_2007_11_12_messpunkt_minute_tag_idx on
> messungen_v_dat_2007_11_12 m  (cost=0.00..5371.09 rows=3204 width=4)
> (actual time=0.152..12.385 rows=2950 loops=1)
>          Index Cond: ((ganglinientyp = 'M'::bpchar) AND (992 = minute_tag))
>    ->  Index Scan using messwerte_mv_nr_idx on messwerte_mv w
> (cost=0.00..8.49 rows=1 width=18) (actual time=0.730..0.734 rows=1
> loops=2950)
>          Index Cond: (w.nr = m.messpunkt)
>  Total runtime: 2234.143 ms
> (6 rows)

> To me this plan looks very clean and nearly optimal,

For so many rows I'm surprised it's not using a bitmap indexscan.
What PG version is this?  How big are these tables?

            regards, tom lane

Re: Join Query Perfomance Issue

From
Thomas Zaksek
Date:
> For so many rows I'm surprised it's not using a bitmap indexscan.
> What PG version is this?  How big are these tables?
>
>             regards, tom lane

Its PG 8.2.6 on Freebsd.

messungen_v_dat_2007_11_12 ist about 4 million rows and messwerte is
about 10 million rows.


Re: Join Query Perfomance Issue

From
"Scott Marlowe"
Date:
On Feb 12, 2008 4:11 AM, Thomas Zaksek <zaksek@ptt.uni-due.de> wrote:

> I tried turning off nestloop, but with terrible results:

Yeah, it didn't help.  I was expecting the query planner to switch to
a more efficient join plan.

> I also tried to increase work_men, now the config is
> work_mem = 4MB

Try setting it higher for JUST THIS query.  i.e.

set work_mem=128M;
explain analyze select ....

and see how that runs.  Then play with it til you've got it down to
what helps.  Note that work_mem in postgresql.conf being too large can
be dangerous, so it might be something you set for just this query for
safety reasons.

Re: Join Query Perfomance Issue

From
Thomas Zaksek
Date:
Scott Marlowe schrieb:
>
> Yeah, it didn't help.  I was expecting the query planner to switch to
> a more efficient join plan.
>
>
> Try setting it higher for JUST THIS query.  i.e.
>
> set work_mem=128M;
> explain analyze select ....
>
> and see how that runs.  Then play with it til you've got it down to
> what helps.  Note that work_mem in postgresql.conf being too large can
> be dangerous, so it might be something you set for just this query for
> safety reasons.
>
>
Tried some values for work_mem like 32M, 128M, 256M, not much of a
difference to 4M, so i think work_mem is high enough here in basic
configuration.

I have now kind of optimized the query to a join of to tables(using
materialized views), basically like this:

SELECT  foo
        FROM messungen_v_dat_2007_11_12 m
            INNER JOIN messwerte_mv p ON p.nr = m.messpunkt
                    WHERE  m.ganglinientyp = 'M'
            AND xxx = m.minute_tag;


Are there any major flaws in this construction? Is there a better way to
join two tables this way?
Best i get here is a runtime of about 100ms, what seems ok to me.
The plan is like

nested loop
        index scan
        index scan

Nested Loop  (cost=0.00..31157.91 rows=3054 width=14) (actual
time=0.252..149.557 rows=2769 loops=1)
   ->  Index Scan using
messungen_v_dat_2007_11_12_messpunkt_minute_tag_idx on
messungen_v_dat_2007_11_12 m  (cost=0.00..5134.28 rows=3054 width=4)
(actual time=0.085..11.562 rows=2769 loops=1)
         Index Cond: ((ganglinientyp = 'M'::bpchar) AND (799 = minute_tag))
   ->  Index Scan using messwerte_mv_nr_idx on messwerte_mv p
(cost=0.00..8.51 rows=1 width=18) (actual time=0.031..0.035 rows=1
loops=2769)
         Index Cond: (p.nr = m.messpunkt)
 Total runtime: 159.703 ms
(6 rows)

Nested Loop is not the best regarding to performance, but there isn't a
way to avoid it here?

Another strange problem occurs when i retry the query after about 12
hours break without akivity on the database (starting work in the
morning) :
The query runs incredible slow (~3sec), analyse on the tables doesn't
change much. But when i switch enable_netloop to false, retry the query
(very bad result, > 30sec), then set enable_nestloop back to true, the
query works amazingly fast again (100ms). Note that explain analyse
provides the exactly similar plan for the 3sec at the beginning and the
fast 100ms later. I have absolutly no idea what causes this behavior.

Re: Join Query Perfomance Issue

From
Chris
Date:
> Nested Loop  (cost=0.00..31157.91 rows=3054 width=14) (actual
> time=0.252..149.557 rows=2769 loops=1)
>   ->  Index Scan using
> messungen_v_dat_2007_11_12_messpunkt_minute_tag_idx on
> messungen_v_dat_2007_11_12 m  (cost=0.00..5134.28 rows=3054 width=4)
> (actual time=0.085..11.562 rows=2769 loops=1)
>         Index Cond: ((ganglinientyp = 'M'::bpchar) AND (799 = minute_tag))
>   ->  Index Scan using messwerte_mv_nr_idx on messwerte_mv p
> (cost=0.00..8.51 rows=1 width=18) (actual time=0.031..0.035 rows=1
> loops=2769)
>         Index Cond: (p.nr = m.messpunkt)
> Total runtime: 159.703 ms
> (6 rows)
>
> Nested Loop is not the best regarding to performance, but there isn't a
> way to avoid it here?

Your own tests have proven it's the right approach for this particular
query.

> Another strange problem occurs when i retry the query after about 12
> hours break without akivity on the database (starting work in the
> morning) :
> The query runs incredible slow (~3sec), analyse on the tables doesn't
> change much. But when i switch enable_netloop to false, retry the query
> (very bad result, > 30sec), then set enable_nestloop back to true, the
> query works amazingly fast again (100ms).

The o/s has cached some of the data so instead of actually hitting the
disk, it's getting it from the o/s cache.

--
Postgresql & php tutorials
http://www.designmagick.com/