pg.ddx.io  pgsql-performance@postgresql.org mailing list archive  
help / color / mirror / Atom feed
From: Heikki Linnakangas <heikki@enterprisedb.com>
To: arnaulist@andromeiberica.com
Cc: PostgreSQL Performance <pgsql-performance@postgresql.org>
Subject: Re: Advice about how to delete
Date: Fri, 06 Jul 2007 17:18:53 +0100
Message-ID: <468E6B6D.1010601@enterprisedb.com> (raw)
In-Reply-To: <468E54D7.8020807@andromeiberica.com>
References: <468E54D7.8020807@andromeiberica.com>

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



view thread (4+ messages)

Message-ID: <468E6B6D.1010601@enterprisedb.com>
Permalink:  ../468E6B6D.1010601@enterprisedb.com/
Also on:    postgresql.org/message-id/468E6B6D.1010601@enterprisedb.com

 · 

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: pgsql-performance@postgresql.org
  Cc: heikki@enterprisedb.com, arnaulist@andromeiberica.com
  Subject: Re: Advice about how to delete
  In-Reply-To: <468E6B6D.1010601@enterprisedb.com>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox