在sqlite中,主要有兩種表型別,帶rowid的表和不帶rowid的表。我們利用create table 建一張表,預設都會有乙個隱含名字為rowid的主鍵,暫且稱帶rowid的表為普通表。如果建表時指定 without rowid屬性,那麼建的表就是不帶rowid的表。那麼這兩種表有什麼區別?這篇文章主要討論這兩種表的儲存實現,以及它們的優缺點和適用的應用場景。
1.rowid是什麼?
sqlite中rowid是乙個隱身儲存的列,8個位元組儲存,它有兩個別名 _rowid_ 和 oid,型別定義為integer primary key,因此當使用者建表時,某列定義為 integer primary key,實質是rowid的別名。rowid是自增的,當該列插入null時, 會取當前表的最大值+1,作為該列的值。注意integer與int不同,比如若列定義為 int primary key, 則插入null值,該列的值就是null,rowid依然會遞增。查詢可以通過select rowid from tablename得到rowid的值。為什麼integer與int不同,可以參考sqlite資料型別。
2.autoincrement屬性
在sqlite中,autoincrement屬性只能用於定義為integer primary key的列,否則建表時會報錯。沒有autoincrement屬性的rowid始終取當前最大值+1,若刪除了最大rowid所在的記錄,導致這個rowid會重用。 採用autoincrement屬性可以避免重用情況,系統內部通過sqlite_sequence表來維護每個表的最大sequence值, 因此即使有刪除情況,也不會導致rowid重用,嚴格單調遞增,代價是執行插入時, 需要維護sqlite_sequence表,對效能有一定的損耗。 由於rowid採用8個位元組儲存,因此上限值為9223372036854775807,當超過這個值時,rowid屬性會隨機選擇乙個值, 只要不與表中已有記錄衝突即可;而autoincrement屬性則會提示error: database or disk is full。
3.儲存區別
普通表的primray key實質是乙個唯一索引,表資料按rowid組織(聚集索引), 通過主鍵訪問表,實質需要訪問唯一索引和聚簇索引,但對於integer primary key除外, 它是rowid的乙個別名,索引實質就是聚簇索引。在sqlite中,聚集索引採用b*樹儲存(b*樹是b+的乙個特例,非葉子節點間也通過雙向指標相連),而普通索引(二級索引,唯一索引)採用b-樹儲存,b+樹與b樹的區別在於,b+樹中非葉子節點只有key資訊,葉子節點包含了key和value資訊,並且葉子節點包含了所有key資訊,key資訊在葉子節點和非葉子節點儲存了兩遍,葉子節點間有雙向指標相連;而b-樹中,葉子節點和非葉子節點結構相同,都包含了key和value資訊,查詢可能在非葉子節點找到資料,直接返回。
without rowid表採用b-tree,葉子節點和非葉子節點都有記錄所有內容, 因此若記錄較長(超過page_size*1/20),扇出(節點記錄數)很小,容易造成節點頻繁**,不適合使用without rowid屬性, 。without rowid 表只有一顆b-樹,訪問只需要訪問一次b-樹, 而普通表需要訪問兩次(索引+表),對於integer primary key除外。without rowid不支援autoincrement屬性,並且primary key不能為null,普通表比較**,primary key 屬性列也可以為null(由於歷史原因,沒有修改)。
4. 例子
(1).普通表
create table if not exists wordcount1(
word text primary key,
cnt integer
);
wordcount1是乙個普通表,底層採用兩顆b樹儲存,一顆b*樹儲存的是表內容,key為rowid,value為(word,cnt);另一顆b-樹是主鍵索引,key為(word,rowid)。因此對於每個word,都會在兩顆b樹中分別存一次。假設我們要查詢word為"xyzzy"的記錄:
select cnt from wordcount1 where word='xyzzy';
為了得到結果,首先需要通過主鍵索引找到rowid,然後再以rowid為key查詢表,得到cnt,總共需要查詢兩次b樹。
(2).without rowid表
create table if not exists wordcount2(
word text primary key,
cnt integer
) without rowid;
wordcount2是without rowid表,底層只有一顆b-樹,即主鍵索引,相對於wordcount1表,wordcount2表中word只需儲存一次。如果查詢word為"xyzzy"的記錄,只需查詢一顆b樹即可。因此在這種情況下,without rowid表不僅節省了儲存,而且查詢效率也比普通表效率高。4.如何選擇表型別?
1) 若主鍵為整型,採用普通表,將列定義為integer primary key,這樣保證只有只有1顆b*樹,提高查詢效率;
2) 若主鍵為非整型,記錄比較小(不超過page_size*1/20),並且不依賴於rowid的邏輯序號,可以考慮使用without rowid表,節省空間 的同時,提高查詢效率
3) 其它情況,則使用普通表,定義主鍵。
5.參考文件
sqlite的字段型別選擇
下文來自 char varchar text和nchar nvarchar ntext的區別 1 char。char儲存定長資料很方便,char欄位上的索引效率級高,比如定義char 10 那麼不論你儲存的資料是否達到了10個位元組,都要占去10個位元組的空間,不足的自動用空格填充。2 varcha...
SQLite的使用一
1sqlite3 test.db 如果顯示以下資訊,則說明sqlite已成功安裝 12 3 4 5 macbook pro md313 sql mac sqlite3 test.db sqlite version 3.7.12 2012 04 03 19 43 07 enter help forin...
SQLite 簡單使用(一)
sqlite 使用 新增列 alter table user add column sync state integer not null default 1 建立表 create table if not exists localuser uid integer not null primary ...