Question: How do I use DEFAULT AUTOINCREMENT for a legacy table I can't change?
It's common to encounter a certain [cough] reluctance to modify the schema of tables that have been around forever and ever. Sometimes, it's almost impossible... you can modify the application code to your heart's content, even add new tables, but not modify any of the old ones... even if you're suffering from a performance problem.
For example, let's say there are concurrency problems caused by a flawed primary key generation process, and you want to use DEFAULT AUTOINCREMENT to fix those problems, but you can't.
Answer: It is possible to obtain the concurrency benefits of DEFAULT AUTOINCREMENT without modifying the schema; you use empty shadow tables instead, and call GET_IDENTITY().
First, here are a couple of legacy tables t1 and t2, followed by corresponding shadow tables:
Here's how the application code can be modified to call GET_IDENTITY() before each INSERT:
CREATE TABLE t1 ( pkey INTEGER NOT NULL PRIMARY KEY, data INTEGER NOT NULL ); CREATE TABLE t2 ( pkey INTEGER NOT NULL PRIMARY KEY, data INTEGER NOT NULL ); CREATE TABLE empty_shadow_t1 ( pkey INTEGER NOT NULL PRIMARY KEY DEFAULT AUTOINCREMENT ); CREATE TABLE empty_shadow_t2 ( pkey INTEGER NOT NULL PRIMARY KEY DEFAULT AUTOINCREMENT );
If that code is executed twice, by two different connections, the tables look like this:
BEGIN DECLARE @pkey1 INTEGER; DECLARE @pkey2 INTEGER; SET @pkey1 = GET_IDENTITY ( 'empty_shadow_t1', 1 ); INSERT t1 VALUES ( @pkey1, 0 ); COMMIT; SET @pkey2 = GET_IDENTITY ( 'empty_shadow_t2', 1 ); INSERT t2 VALUES ( @pkey2, 0 ); COMMIT; SET @pkey1 = GET_IDENTITY ( 'empty_shadow_t1', 1 ); INSERT t1 VALUES ( @pkey1, 0 ); COMMIT; SET @pkey2 = GET_IDENTITY ( 'empty_shadow_t2', 1 ); INSERT t2 VALUES ( @pkey2, 0 ); COMMIT; SET @pkey1 = GET_IDENTITY ( 'empty_shadow_t1', 1 ); INSERT t1 VALUES ( @pkey1, 0 ); COMMIT; SET @pkey2 = GET_IDENTITY ( 'empty_shadow_t2', 1 ); INSERT t2 VALUES ( @pkey2, 0 ); COMMIT; SELECT * FROM t1 ORDER BY pkey; SELECT * FROM t2 ORDER BY pkey; END;
Here's how SET @pkey1 = GET_IDENTITY ( 'empty_shadow_t1', 1 ); works:
pkey data ----------- ----------- 1 0 2 0 3 0 4 0 5 0 6 0 pkey data ----------- ----------- 1 0 2 0 3 0 4 0 5 0 6 0
xxx
- It uses the DEFAULT AUTOINCREMENT specification on the column empty_shadow_t1.pkey to generated the next auto-increment value.
- It modifies the corresponding SYSTABCOL.max_identity column value to reflect the fact that generated value has been reserved.
SELECT SYSTAB.table_name, SYSTABCOL.column_name, SYSTABCOL.max_identity FROM SYSTAB INNER JOIN SYSTABCOL ON SYSTAB.table_id = SYSTABCOL.table_id WHERE SYSTAB.table_name LIKE 'empty%' ORDER BY SYSTAB.table_name; table_name column_name max_identity ----------------- ----------------- ----------------- empty_shadow_t1 pkey 6 empty_shadow_t2 pkey 6
- It returns the generated value as the GET_IDENTITY() result.
Which is a good thing, because most DBAs don't mind it if you ask for an empty table :)
No comments:
Post a Comment