问题
I am trying to use a partitioned table in postgresql together with a Django installation.
From Googleing the subject, I found out, that Django does not support partitioning by itself, so I did the partitioning of the table myself. I partition my table based on a second field which is a foreign key on another table. The basic model setup is like so:
class Event(models.Model):
id = models.AutoField(primary_key=True)
device = models.ForeignKey("Device")
... (More Fields)
I have Partitioned the table by the device_id, generating subtables like event_1, event_2 etc. All my querys contain the device id, so the querys are much faster now, but for inserting, django generates an UPDATE Statement like:
UPDATE event SET device=X, ...=X, ... WHERE id=XXX
This results in the database traversing all the partitions of the table to look for the specified ID. Since the device_id never changes, I now want to add the device_id=XXX statement into the WHERE part of the UPDATE statement, which would allow the database to only traverse the one partition.
I think my problem is only a result of the problem, that I don't have the partitioning key in the primary key of my database, but since django only supports one field to be the PK and the partitioning key is not unique, I can't use it as PK.
I can think of two solutions to my problem:
- Use a primary key field, that is somehow automatically constructed from an increasing number combined with the device_id (like 1_234). The database would then have to split the primary key to know which device this event is for and which partition it needs to search in.
- Change the UPDATE Statement, such that it adds the device_id to the WHERE statement.
The most elegant way in my opinion would be to include the device_id in the primary key. Therefore no changes in Django would be needed and the partitioning would happen only in the database transparent for Django. However I'm not sure if it is possible to create such a primary key in the database.
Thank you for your Help
回答1:
I agree that you would probably be best to leave Django out of it. While I've never done something exactly like this, I think it would be pretty easy to just create a before insert trigger to construct your new, concatenated primary key. Something like this:
CREATE TABLE foo(
id TEXT NOT NULL,
device_id INT NOT NULL,
CONSTRAINT foo_pkey PRIMARY KEY (id)
);
CREATE SEQUENCE foo_id_seq
INCREMENT 1
MINVALUE 1
MAXVALUE 9223372036854775807
START 1
CACHE 1;
CREATE OR REPLACE FUNCTION generate_foo_id()
RETURNS trigger AS
$BODY$
BEGIN
NEW.id := NEW.device_id || '_' || nextval('foo_id_seq');
RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
CREATE TRIGGER trigger_generate_foo_id
BEFORE INSERT
ON foo
FOR EACH ROW
EXECUTE PROCEDURE generate_foo_id();
And you are right, your partition function will have to split it. I've never created a partition function that does this, but I don't know why it would not work. However, you should test and add a comment to this 'answer' with your results (so that future users will benefit from your testing).
来源:https://stackoverflow.com/questions/19706043/django-save-object-based-on-pk-and-another-field