Received: from localhost (maia-2.hub.org [200.46.204.187]) by postgresql.org (Postfix) with ESMTP id DAAFC9FB51D for ; Mon, 9 Apr 2007 18:08:16 -0300 (ADT) Received: from postgresql.org ([200.46.204.71]) by localhost (mx1.hub.org [200.46.204.187]) (amavisd-maia, port 10024) with ESMTP id 86979-05 for ; Mon, 9 Apr 2007 18:08:01 -0300 (ADT) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.4 Received: from wx-out-0506.google.com (wx-out-0506.google.com [66.249.82.232]) by postgresql.org (Postfix) with ESMTP id 199029FB735 for ; Mon, 9 Apr 2007 18:08:05 -0300 (ADT) Received: by wx-out-0506.google.com with SMTP id i28so1488456wxd for ; Mon, 09 Apr 2007 14:08:04 -0700 (PDT) DKIM-Signature: a=rsa-sha1; c=relaxed/relaxed; d=gmail.com; s=beta; h=domainkey-signature:received:received:message-id:date:from:to:subject:cc:in-reply-to:mime-version:content-type:content-transfer-encoding:content-disposition:references; b=lPri40FtaauICH5PNn7h9I9zq8Fncts+DCn+f9m43RCOBGO1h6h303vM1drZVwTDlLCGPmIaA57sjs6aGv6VY4SUJpyy6VgePZrwIhQRfYDdI69NxjFyIo+pKZSkN7arOsQkr6yWHq2N9VbI61AjGUVqI5fHdDXlDM7LL2FFouM= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=beta; h=received:message-id:date:from:to:subject:cc:in-reply-to:mime-version:content-type:content-transfer-encoding:content-disposition:references; b=jlAU/sc9IL1LaBqlH4D3xykwQeBMedCBQJsTAPdlH/EGob9MUh5w5KSRdtMccmOdzdQ2b6aa93CEYmXarhU5wnLp7rQydoIBIq60sy/stPaX0FhL19bhnHrKiXrWZ2gdIKUJAJOUQv0EKvmhhtMq2O9fbCbUnd9b3O/6/RbKJbM= Received: by 10.78.97.7 with SMTP id u7mr929644hub.1176152882986; Mon, 09 Apr 2007 14:08:02 -0700 (PDT) Received: by 10.78.35.18 with HTTP; Mon, 9 Apr 2007 14:08:02 -0700 (PDT) Message-ID: Date: Mon, 9 Apr 2007 17:08:02 -0400 From: "Merlin Moncure" To: "Drew Wilson" Subject: Re: how to efficiently update tuple in many-to-many relationship? Cc: pgsql-performance@postgresql.org In-Reply-To: <233A9987-ABA5-4491-A304-FDA1F8FCD962@gmail.com> MIME-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Content-Disposition: inline References: <233A9987-ABA5-4491-A304-FDA1F8FCD962@gmail.com> X-Virus-Scanned: Maia Mailguard 1.0.1 X-Archive-Number: 200704/215 X-Sequence-Number: 24092 On 4/9/07, Drew Wilson wrote: > I have 2 tables (A,B) joined in a many-to-many relationship via a > join table ("membership"), where updating table A based on table B > takes a very long time. > > Tables A and B have oid primary keys (a_id and b_id respectively). > The join table, "membership", has its own oid primary key > (membership_id), as well as foreign keys "a_id" and "b_id". > > A SELECT query across all 3 tables takes 12 seconds. > "SELECT count(*) FROM a JOIN membership USING(a_id) JOIN b USING > (b_id) WHERE b.is_public = true" > > But a simple UPDATE using the same SELECT query takes 30 minutes to > an hour. > "UPDATE A set is_public=true WHERE a_id IN (SELECT count(*) FROM a > JOIN membership USING(a_id) JOIN b USING(b_id) WHERE b.is_public = > true)". > > What am I doing wrong here? I'm not sure how to diagnose this further. > > Here's the output from explain: > db=# EXPLAIN SELECT a_id FROM a JOIN membership USING(a_id) JOIN b > USING(b_id) WHERE b.is_public = true; > ------------------------------------------------------------------------ > ----------------------------------------- > Hash Join (cost=167154.78..173749.48 rows=51345 width=4) > Hash Cond: (a.a_id = membership.a_id) > -> Function Scan on a (cost=0.00..12.50 rows=1000 width=4) > -> Hash (cost=144406.48..144406.48 rows=1819864 width=4) > -> Hash Join (cost=417.91..144406.48 rows=1819864 width=4) > Hash Cond: (membership.b_id = b.b_id) > -> Seq Scan on membership (cost=0.00..83623.83 > rows=4818983 width=8) > -> Hash (cost=348.52..348.52 rows=5551 width=4) > -> Index Scan using b_is_public on b > (cost=0.00..348.52 rows=5551 width=4) > Index Cond: (is_public = true) > Filter: is_public > (11 rows) > > > db=# EXPLAIN UPDATE a SET is_public = true WHERE a_id IN > ( SELECT a_id FROM a JOIN membership USING(a_id) JOIN b USING > (b_id) WHERE b.is_public = true); > ------------------------------------------------------------------------ > ----------------------------------------- > hash in join (cost=281680.17..370835.63 rows=1819864 width=90) > hash cond: (public.a.a_id = public.a.a_id) > -> seq scan on a (cost=0.00..47362.09 rows=2097309 width=90) > -> hash (cost=258931.87..258931.87 rows=1819864 width=8) > -> hash join (cost=73996.36..258931.87 rows=1819864 width=8) > hash cond: (membership.a_id = public.a.a_id) > -> hash join (cost=417.91..144406.48 rows=1819864 > width=4) > hash cond: (membership.b_id = b.b_id) > -> seq scan on membership > (cost=0.00..83623.83 rows=4818983 width=8) > -> hash (cost=348.52..348.52 rows=5551 width=4) > -> index scan using > loc_submission_is_public on b (cost=0.00..348.52 rows=5551 width=4) > index cond: (is_public = true) > filter: is_public > -> hash (cost=47362.09..47362.09 rows=2097309 width=4) > -> seq scan on a (cost=0.00..47362.09 > rows=2097309 width=4) why don't you rewrite your update statement to use joins (joins > where exists > where in)? WHERE a_id IN (SELECT count(*) FROM a the above looks wrong maybe? merlin