Received: from localhost (unknown [200.46.204.183]) by mail.postgresql.org (Postfix) with ESMTP id 0CB9B634336 for ; Thu, 2 Apr 2009 16:32:09 -0300 (ADT) Received: from mail.postgresql.org ([200.46.204.86]) by localhost (mx1.hub.org [200.46.204.183]) (amavisd-maia, port 10024) with ESMTP id 71969-06 for ; Thu, 2 Apr 2009 16:32:07 -0300 (ADT) X-Greylist: from auto-whitelisted by SQLgrey-1.7.6 Received: from sss.pgh.pa.us (sss.pgh.pa.us [66.207.139.130]) by mail.postgresql.org (Postfix) with ESMTP id 40592634301 for ; Thu, 2 Apr 2009 16:32:07 -0300 (ADT) Received: from sss2.sss.pgh.pa.us (tgl@localhost [127.0.0.1]) by sss.pgh.pa.us (8.14.2/8.14.2) with ESMTP id n32JW4X4016809; Thu, 2 Apr 2009 15:32:04 -0400 (EDT) To: Tony Cebzanov cc: pgsql-sql@postgresql.org Subject: Re: Performance problem with row count trigger In-reply-to: <49D4CA3A.3050005@andrew.cmu.edu> References: <49D4CA3A.3050005@andrew.cmu.edu> Comments: In-reply-to Tony Cebzanov message dated "Thu, 02 Apr 2009 10:22:50 -0400" Date: Thu, 02 Apr 2009 15:32:03 -0400 Message-ID: <16805.1238700723@sss.pgh.pa.us> From: Tom Lane X-Virus-Scanned: Maia Mailguard 1.0.1 X-Spam-Status: No, hits=0 tagged_above=0 required=5 tests=none X-Spam-Level: X-Archive-Number: 200904/18 X-Sequence-Number: 32364 Tony Cebzanov writes: > What I want to do is update the assoc_count field in the dataset table > to reflect the count of related records in the assoc field. To do so, I > added the following trigger: > CREATE OR REPLACE FUNCTION update_assoc_count_insert() > RETURNS TRIGGER AS > ' > BEGIN > UPDATE dataset > SET assoc_count = assoc_count + 1 > WHERE dataset_id = NEW.dataset_id; > RETURN NEW; > END > ' LANGUAGE plpgsql; > CREATE TRIGGER assoc_update_assoc_count_insert AFTER INSERT ON assoc > FOR EACH ROW EXECUTE PROCEDURE update_assoc_count_insert(); There is basically no way that this is going to not suck :-(. In the first place, using an AFTER trigger means that each update queues an AFTER trigger update event that has to be fired at statement or transaction end. In the second place (as Craig correctly noted) this results in a separate update to the count-table row for each inserted row, which tremendously bloats the count table with dead tuples. In the third place, if you have any concurrency of insertions, it disappears because all the inserters need to update the same count row. If you dig in the pgsql-hackers archives, you will find that the original scheme for this was to have each transaction accumulate its total number of insertions minus deletions for a table in local memory, and then insert *one* delta row into the count table just before transaction commit. I don't think it's possible to do that with just user-level triggers (not least because we haven't got ON COMMIT triggers); it would have to be a C-code addition. The various blog entries you cite are non-peer-reviewed oversimplifications of that design. Digging around, the oldest description I can find of this idea is http://archives.postgresql.org/pgsql-hackers/2003-09/msg00387.php although there are more recent threads rehashing the topic. One point I don't recall anyone mentioning is that the stats subsystem now implements a fairly large subset of this work already, namely the initial data accumulation. So you could imagine plugging something into that to send the deltas to a table in addition to the stats collector. regards, tom lane