Re: Very slow joins

From: MS <fretka1990(at)gmail(dot)com>
To: pgsql-general(at)postgresql(dot)org
Subject: Re: Very slow joins
Date: 2009-07-27 11:20:39
Message-ID: c1bb5103-1781-4d3d-abfa-e8f97fd3b47f@w6g2000yqw.googlegroups.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-general

> What first post? The only thing I can find is a reference in a message  
> by you from yesterday, to a two-year old post that you claim is about  
> the same problem. Though it's possible that it is the same problem,  
> you don't provide any data to back that up.

Strange - you can see the full thread here:
http://groups.google.pl/group/pgsql.general/browse_thread/thread/6c4ea8356327276c
I post via Google, maybe that's the cause?

> The message you referred to was about a one-of-a-kind problem with  
> communications to the client and had nothing to do with performance on  
> the server; is that indeed what you're seeing? In that case you should  
> check your network infrastructure for problems.

No, I actually meant that the CPU usage was low during my query.
On the other hand IO wait was very high so the low CPU usage was kind
of normal.

> Usually server performance problems are due to problems with tuning  
> parameters or outdated statistics. Those issues can usually be solved  
> easily.

Well, maybe - I started to use postgres only recently, so maybe I'm
doing some obvious
mistakes. My database was filled incrementally by a shell script - I
don't know if that alone lets
postgres collect all necessary stats. Maybe an implicit analyze is
necessary?

I also tried to vacuum/vacuum full my tables before running my queries
but it took too long so I had to break it.

> Without posting an EXPLAIN ANALYSE people here can only guess what  
> your problem is.

I'm posting another "explain analyze" below.
I've run my query with "explain analyze", but forgot to save it :( I
think I won't be able to run my queries again, because
they took around 30-60 minutes and almost killed my server (was almost
completely unresponsive during
the query, because of 90% IO wait).

> > BUT I found the real cause of my problem - the "fk2" field from my
> > example had not only an index, but it was also a foreign key to
> > another table.
> That seems unlikely to be the cause. From the above it seems much more  
> likely that you're suffering from a bad query plan instead, but you  
> don't provide any details.

I just tried to create a test with similar data - here is what it
looks like:
(it should work if you just paste it in some Test db)

-- ------------- generate test tables + data

drop table if exists article, keyword, article_keyword, tochange, sums
cascade;

CREATE TABLE "article" (
"id" serial NOT NULL PRIMARY KEY,
"content" varchar(255) NULL,
"ip" inet NULL,
"has_comments" bool not null
)
;

CREATE TABLE "keyword" (
"id" serial NOT NULL PRIMARY KEY,
"keyword" varchar(40) NOT NULL UNIQUE,
"articles" integer NOT NULL
)
;
CREATE TABLE "article_keyword" (
"id" serial NOT NULL PRIMARY KEY,
"article_id" integer NOT NULL REFERENCES "article" ("id")
DEFERRABLE INITIALLY DEFERRED,
"keyword_id" integer NOT NULL REFERENCES "keyword" ("id")
DEFERRABLE INITIALLY DEFERRED,
"votes_yes" integer NOT NULL,
"votes_no" integer NOT NULL
)
;
CREATE INDEX "article_keyword_keyword_id" ON
"article_keyword" ("keyword_id");

insert into article(content, ip, has_comments) values ('some article',
'123.121.121.223', true);

insert into keyword
select nextval('keyword_id_seq'), md5(to_char(i, '9999999999999')), 0
from generate_series(1,2000000) as i;

insert into article_keyword
select nextval('article_keyword_id_seq'), 1, k.id, 0, 0 from
generate_series(1,2000000) as i
join keyword k on k.keyword=md5(to_char(i, '9999999999999'))
join generate_series(1,5) as times on true
;

create table tochange (
fromid int not null primary key,
toid int not null
);

insert into tochange
select k1.id, k2.id from
generate_series(1,200000) as i
join keyword k1 on k1.keyword=md5(to_char(i, '9999999999999'))
join keyword k2 on k2.keyword=md5(to_char(i+200000, '9999999999999'))
;

create table sums (
id int not null primary key,
sum int
);

-- ----------------- now my queries:

-- replace fromid's with toid's

update article_keyword
set keyword_id=tc.toid
from tochange tc
where
keyword_id=tc.fromid
;

-- delete unused keywords
delete from article_keyword
where id in (
select k.id
from keyword k
left join article_keyword ak on k.id=ak.keyword_id
where ak.keyword_id is null
)
;

-- recalculate sums - in how many articles is a keyword used?
insert into sums
select keyword_id, count(*)
from article_keyword
group by keyword_id;

update keyword k
set articles=s.sum
from
sums s
where
k.id=s.id;

----------------------

The problem is that I can't reproduce this slow behaviour with this
test case. :(
The tables are almost identical - only the article table is bigger in
reality (it has around million rows)

When I run "explain update" (first update from the test case) it
prints this now:

Merge Join (cost=5.14..53436.13 rows=3636710 width=26)
Merge Cond: (tc.fromid = article_keyword.keyword_id)
-> Index Scan using tochange_pkey on tochange tc
(cost=0.00..2830.26 rows=100000 width=8)
-> Index Scan using article_keyword_keyword_id on article_keyword
(cost=0.00..148216.29 rows=5000040 width=26)
(4 rows)

When I disable enable_mergejoin I have this plan:

Hash Join (cost=6160.91..274121.21 rows=5500010 width=26)
Hash Cond: (article_keyword.keyword_id = tc.fromid)
-> Seq Scan on article_keyword (cost=0.00..87353.10 rows=5500010
width=26)
-> Hash (cost=2882.74..2882.74 rows=199774 width=8)
-> Seq Scan on tochange tc (cost=0.00..2882.74 rows=199774
width=8)
(5 rows)

This is the plan I was getting with my original query which took so
long.

Also the second Update was very slow. Deletes, and inserts were quite
fast.

> It would also help to know what version of PostgreSQL this is and on  
> what hardware and setup you're running into this issue.

I tried both postgress 8.3, and 8.4. Now I use 8.4.

I have a standard config + pgtune which added the following entries:
default_statistics_target = 50
maintenance_work_mem = 28MB
constraint_exclusion = on
checkpoint_completion_target = 0.9
effective_cache_size = 352MB
work_mem = 2816kB
wal_buffers = 8MB
checkpoint_segments = 16
shared_buffers = 112MB
max_connections = 80

The server is Intel(R) Core(TM)2 CPU E8400 @3.00GHz, 4GB ram, 2x
SATA disks in Raid1

Thanks,
MS

In response to

Responses

Browse pgsql-general by date

  From Date Subject
Next Message MS 2009-07-27 11:36:58 Re: Very slow joins
Previous Message tomrevam 2009-07-27 08:23:10 Re: synchronous_commit=off doesn't always return immediately