Database Design Advice

Philip Skinner me at philip-skinner.co.uk
Mon Nov 18 11:18:24 GMT 2013


Auto-increment a double column primary key, something like:

uid int(11) not null auto_increment, revision int(11) not null 
auto_increment, primary key(uid, revision)

; works in mysql. You won't have your concurrent query issues there, for 
the most part anyway. Maybe marking a records as tainted.

On 11/18/2013 10:25 AM, Smylers wrote:
> Dagfinn Ilmari Mannsåker writes:
>
>> Smylers <Smylers at stripey.com> writes:
>>
>>> Here it is in Postgres's own function language, which goes by the
>>> awkwardly written name PL/pgSQL:
>>>
>>>    CREATE OR REPLACE FUNCTION set_document_version_num() RETURNS TRIGGER AS
>>>    $FN$
>>>      BEGIN
>>>        NEW.version := 1 +
>>>            MAX(version)
>>>            FROM document_version
>>>            WHERE document_id = NEW.document_id;
>>>        RETURN NEW;
>>>      END;
>>>    $FN$ LANGUAGE plpgsql;
>>>
>>>    CREATE TRIGGER insert_document_version_num
>>>    BEFORE INSERT ON document_version FOR EACH ROW
>>>    EXECUTE PROCEDURE set_document_version_num();
>> This trigger works fine, until you get concurrent saves of the same
>> document, in which case one of the transactions will get a duplicate key
>> violation.
> Ah, thank you for pointing that out.
>
> In this case I think having a collision, and hence an error, may
> actually be desirable: the application can detect the error and warn the
> user that another change has already been made.
>
>> If you want both to succed, with the last one winning, you can do it
>> by keeping the current version in the document table,
> I had been thinking that doing that would be bad, because it's
> redundant, even though having it looks like it'd be convenient in a few
> places.
>
>> and making the trigger update it:
> But that sounds quite nice, the duplication seems liveable-with when
> it's managed with a trigger.
>
>>    ALTER TABLE document
>>      ADD COLUMN current_version INTEGER NOT NULL DEFAULT 0;
>>
>>    REPLACE FUNCTION set_document_version_num() RETURNS TRIGGER AS
>>    $FN$
>>      BEGIN
>>        UPDATE document
>>          SET current_version = current_version + 1
>>          WHERE id = NEW.document_id
>>          RETURNING current_version
>>          INTO NEW.version;
>>        RETURN NEW;
>>      END
>>    $FN$ LANGUAGE plpgsql;
> I do like Postgres's RETURNING clauses — they seem so much more flexible
> and elegant than other ways of achieving the same ends.
>
> Cheers
>
> Smylers



More information about the london.pm mailing list