1. 程式人生 > >INTEGER PRIMARY KEY AUTOINCREMENT 和 INTEGER PRIMARY KEY 區別

INTEGER PRIMARY KEY AUTOINCREMENT 和 INTEGER PRIMARY KEY 區別

Sqlite 中INTEGER PRIMARY KEY AUTOINCREMENT和rowid/INTEGER PRIMARY KEY的使用
在用sqlite設計表時,每個表都有一個自己的整形id值作為主鍵,插入後能直接得到該主鍵.
因為sqlite內部本來就會為每個表加上一個rowid,這個rowid可以當成一個隱含的欄位使用,
但是由sqlite引擎來維護的,在3.0以前rowid是32位的整數,3.0以後是64位的整數,可以使用這個內部的rowid作為每個表的id主鍵。
查了下文件:
參照http://www.sqlite.org/c3ref/last_insert_rowid.html
Each entry in an SQLite table has a unique 64-bit signed integer key called the “rowid”.
The rowid is always available as an undeclared column named ROWID, OID,
or ROWID

as long as those names are not also used by explicitly declared columns.
If the table has a column of type INTEGER PRIMARY KEY then that column is another alias for the rowid.
如果表中有個INTEGER PRIMARY KEY欄位,那麼它只是rowid的別名。
This routine returns the rowid of the most recent successful INSERT into the database from the database connection in the first argument.
If no successful INSERTs have ever occurred on that database connection, zero is returned.
如果成功插入一條資料,會返回剛剛插入的資料的rowid.如果失敗返回0.Android中如果發生錯誤返回的是-1
參照
http://www.sqlite.org/faq.html

Short answer: A column declared INTEGER PRIMARY KEY will autoincrement.
Here is the long answer: If you declare a column of a table to be INTEGER PRIMARY KEY,
then whenever you insert a NULL into that column of the table,
the NULL is automatically converted into an integer which is one greater than the largest value of that column over
all other rows in the table, or 1 if the table is empty. (If the largest possible integer key, 9223372036854775807,
then an unused key value is chosen at random.) For example, suppose you have a table like this:
CREATE TABLE t1(
a INTEGER PRIMARY KEY,
b INTEGER
);
With this table, the statement
INSERT INTO t1 VALUES(NULL,123);
is logically equivalent to saying:
INSERT INTO t1 VALUES((SELECT max(a) FROM t1)+1,123);
There is a function named sqlite3_last_insert_rowid() which will return the integer key for the most recent insert operation.
Note that the integer key is one greater than the largest key that was in the table just prior to the insert.
The new key will be unique over all keys currently in the table,
but it might overlap with keys that have been previously deleted from the table.
To create keys that are unique over the lifetime of the table,
add the AUTOINCREMENT keyword to the INTEGER PRIMARY KEY declaration.
Then the key chosen will be one more than than the largest key that has ever existed in that table.
If the largest possible key has previously existed in that table, then the INSERT will fail with an SQLITE_FULL error code.
把一個列申明為INTEGER PRIMARY KEY,那麼在向它插入NULL,該列就由系統指定。該值為已經存在的資料的該列的最大值加1。空表時該值就為1
如果該值已經超過了最大值,那麼它會隨即選擇一個已存資料沒使用過的值做個插入資料的值。
如果使用者在插入時給它指定一個值,那麼返回的也是那個值。
因為本來返回的應該是rowid,但如果表中有個INTEGER PRIMARY KEY欄位,那麼它只是rowid的別名。
所以返回的就是指定的那個值。
把一個列宣告為INTEGER PRIMARY KEY AUTOINCREMENT的話,它的值是選擇的在該表中曾經使用過的最大值+1。
如果達到了最大值的話,會插入失敗,並丟擲an SQLITE_FULL error code。
再參照sqlite的文件:
http://www.sqlite.org/autoinc.html

最後得出以下結論:
用自增長欄位為主鍵有不少問題,比如維護或是在大型分佈應用中主鍵衝突的解決等。在一些大型分佈應用中主鍵一般選用 guid,這可以有效的避免主鍵衝突,減少對主鍵維護的工程
當然,對於中小型的應用,自增長欄位的好處更多一些,簡單、快速。
Sqlite中,一個自增長欄位定義為INTEGER PRIMARY KEY AUTOINCREMENT或者INTEGER PRIMARY KEY時 ,那麼在插入一個新資料時,只需要將這個欄位的值指定為NULL,即可由引擎自動設定其值。
當然,也可以設定為非 NULL的數字來自己指定這個值,但這樣就必須自己小心,不要引起衝突。
對於INTEGER PRIMARY KEY ,當這個rowid的值大於所能表達的最大值 9223372036854775807 (3.0及以後版本的rowid最大值)後,rowid的新值會這個最大數之前隨機找一個沒被使用了的值。
所以在rowid達到最大值前,rowid的值是嚴格單調增加的。
INTEGER PRIMARY KEY AUTOINCREMENT 自增長欄位的演算法與rowid/INTEGER PRIMARY KEY稍微有些不同。
第一,在達到最大值後,rowid/INTEGER PRIMARY KEY會找已被刪除的欄位對應的rowid/INTEGER PRIMARY KEY作為新值,
而自增長欄位INTEGER PRIMARY KEY AUTOINCREMENT則會丟出一個SQLITE_FULL的錯誤。
第二,自增長欄位INTEGER PRIMARY KEY AUTOINCREMENT在增加新值時,是找一個從沒被使用過的值作為新值,而 rowid/INTEGER PRIMARY KEY則是找最大已存在的(rowid/INTEGER PRIMARY KEY)+1。
這裡對應用的影響會比較大,尤其是一些對id值有依賴的元記錄,只適合使用自增長欄位而不能用rowid/INTEGER PRIMARY KEY。
比如,我們設計一個元記錄表:
Create table meta_struct(id INTEGER PRIMARY KEY AUTOINCREMENT, name varchar, type Integer);
然後,定義一個一級表,來描述其它表的結構:
Create table meta_table(tableid INTEGER, table_field integer)
最後,我們的應用可以根據這個一級表來產生實際使用的二級表。
這樣為保證相容性meta_struct中的id必須是唯一的,如果有欄位被刪除,也不能重複使用這個欄位的id值,不然,在資料庫合併時,一級表和二級表就會混亂。
所以meta_struct表中的主鍵只能使用自增長欄位,而不能用rowid。
第三,使用自增長欄位INTEGER PRIMARY KEY AUTOINCREMENT,引擎會自動產生一個sqlite_sequence表,用於記錄每個表的自增長欄位的已使用的最大值,
使用者可以看到,並可以用使用Update、Delete和Insert操作,但不建議這麼使用,這會讓引擎混亂。
如果使用rowid/INTEGER PRIMARY KEY,也會有這麼一個內部表,使用者可以維護rowid/INTEGER PRIMARY KEY值,但看不到。
這麼看來,如果直接使用rowid/INTEGER PRIMARY KEY來代替自增加欄位,根據兩者的細微的差別,需要注意是否與自己的應用衝突,
如果沒有衝突,那麼用rowid/INTEGER PRIMARY KEY會更快一
第四,在android中,對於INTEGER PRIMARY KEY,
如果插入資料A,B,C,它們的_id為1,2,3,那麼如果把他們都刪除了,再插入一條資料,那麼它的id為1而不是4。