Received: from localhost (maia-3.hub.org [200.46.204.184]) by postgresql.org (Postfix) with ESMTP id 164F09FB570 for ; Fri, 6 Jul 2007 13:19:55 -0300 (ADT) Received: from postgresql.org ([200.46.204.71]) by localhost (mx1.hub.org [200.46.204.184]) (amavisd-maia, port 10024) with ESMTP id 08217-06 for ; Fri, 6 Jul 2007 13:19:49 -0300 (ADT) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.5 Received: from ug-out-1314.google.com (ug-out-1314.google.com [66.249.92.170]) by postgresql.org (Postfix) with ESMTP id B4EA79FB358 for ; Fri, 6 Jul 2007 13:19:49 -0300 (ADT) Received: by ug-out-1314.google.com with SMTP id a2so807396ugf for ; Fri, 06 Jul 2007 09:19:48 -0700 (PDT) DKIM-Signature: a=rsa-sha1; c=relaxed/relaxed; d=gmail.com; s=beta; h=domainkey-signature:received:received:message-id:date:from:user-agent:mime-version:to:cc:subject:references:in-reply-to:content-type:content-transfer-encoding:sender; b=fBNFDUYQNk6xpF7y2dIDKfe4ZXniKyyvtnmB9md/9kcYXaMIjcUFEaSTwAXeGx2Bhr9pV+RORmjNtapMVTyKhMHWpq2WFMjjGCRP8LRzbWgZdf0UE4ux6ecwEK7b742Q+3n47QUbf8zrI//zhUj7bCMOE3xmq3RZuhUchnZJer8= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=beta; h=received:message-id:date:from:user-agent:mime-version:to:cc:subject:references:in-reply-to:content-type:content-transfer-encoding:sender; b=HAE20OQhCwbEMYYNO9HRuFsIJNbmBriQUEEmvL86tlf0uOVgacYYpAXIY1b1rsWTfjkiP4kUhjWj3jJQ2s2a9wkNwOQuNBXZCXbplNEXg6l6GQ3m6/sW+ZK9HrpMbznFj8eSM+h9P3AQVqG1QfbtcPWwb3iAqiQMEq5Mtx/YF64= Received: by 10.67.16.2 with SMTP id t2mr2824858ugi.1183738788355; Fri, 06 Jul 2007 09:19:48 -0700 (PDT) Received: from ?192.168.1.33? ( [86.31.148.180]) by mx.google.com with ESMTPS id m1sm1056388uge.2007.07.06.09.19.43 (version=SSLv3 cipher=RC4-MD5); Fri, 06 Jul 2007 09:19:44 -0700 (PDT) Message-ID: <468E6B6D.1010601@enterprisedb.com> Date: Fri, 06 Jul 2007 17:18:53 +0100 From: Heikki Linnakangas User-Agent: Icedove 1.5.0.10 (X11/20070329) MIME-Version: 1.0 To: arnaulist@andromeiberica.com CC: PostgreSQL Performance Subject: Re: Advice about how to delete References: <468E54D7.8020807@andromeiberica.com> In-Reply-To: <468E54D7.8020807@andromeiberica.com> Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit X-Virus-Scanned: Maia Mailguard 1.0.1 X-Archive-Number: 200707/52 X-Sequence-Number: 25736 Arnau wrote: > CREATE TABLE user_groups > ( > user_id INT8 REFERENCES users(user_id), > group_id INT8 REFERENCE groups(group_id), > CONSTRAINT pk PRIMARY_KEY ( user_id, group_id) > ) > > CREATE INDEX idx_user_id ON user_groups( user_id ); The primary key implicitly creates an index on (user_id, group_id), so you probably don't need this additional index. > This works quite fast with small groups but when the group has an > important number of users, it takes too much time. The delete_group > action is fired from the user interface of the application. It looks like you're not deleting rows from user_groups when a group is deleted. Perhaps the table definition you posted misses ON DELETE CASCADE on the foreign key declarations? I would implement this with triggers. Use the ON DELETE CASCADE to take care of deleting rows from user_groups and create an ON DELETE trigger on user_groups to delete orphan rows. Like this: CREATE OR REPLACE FUNCTION delete_orphan_users () RETURNS trigger AS $$ DECLARE BEGIN PERFORM * FROM user_groups ug WHERE ug.user_id = OLD.user_id; IF NOT FOUND THEN DELETE FROM users WHERE users.user_id = OLD.user_id; END IF; RETURN NULL; END; $$ LANGUAGE 'plpgsql'; DROP TRIGGER IF EXISTS d_usergroup ON user_groups; CREATE TRIGGER d_usergroup AFTER DELETE ON user_groups FOR EACH ROW EXECUTE PROCEDURE delete_orphan_users(); This might not be significantly faster, but it's easier to work with. > Do you have any idea about how I could improve the performance of this? Michael Glaesemann's idea of using a single statement to delete all orphan users with one statement is a good one, though you want to refine it a bit so that you don't need to do a full table scan every time. Perhaps like this, before deleting rows from user_groups: DELETE FROM users WHERE user_id IN ( SELECT u.user_id FROM users u LEFT OUTER JOIN user_groups ug ON (u.user_id = ug.user_id AND ug.group_id <> 10) WHERE group_id IS NULL AND u.user_id IN (SELECT user_id FROM user_groups where group_id = 10) ); Or maybe you could just leave the orphans in the table, and delete them later in batch? -- Heikki Linnakangas EnterpriseDB http://www.enterprisedb.com