在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.参考文档

https://www.sqlite.org/withoutrowid.html

SQLite使用(一)&&选择表类型的更多相关文章

  1. mysql————表类型(存储引擎)的选择

    表类型(存储引擎)的选择 7.1 mysql存储引擎概述 插件式存储引擎是mysql数据库最重要的特性之一,用户可以根据应用的需要选择ruhr存储和索引数据,是否使用事务等. InnoDB和BDB提供 ...

  2. 浅谈MySql的存储引擎(表类型)

    来源:http://www.cnblogs.com/lina1006/archive/2011/04/29/2032894.html 什么是MySql数据库 通常意义上,数据库也就是数据的集合,具体到 ...

  3. mysql如何修改表类型(表引擎)

    参考阅读:http://www.manongjc.com/article/1205.html 最近遇到一个修改 MySQL 表类型的问题,以前在 phpmyadmin 管理 mysql 数据库时,建立 ...

  4. MySQL表类型

    学习Mysql数据库,Mysql表类型都有哪些是一定需要知道的,下面就为您介绍七种Mysql表类型,希望能对您学习Mysql表类型有所帮助. MySQL作为当前最为流行的免费数据库服务引擎,已经风靡了 ...

  5. 浅谈MySql的存储引擎(表类型) (转)

    什么是MySql数据库 通常意义上,数据库也就是数据的集合,具体到计算机上数据库可以是存储器上一些文件的集合或者一些内存数据的集合. 我们通常说的MySql数据库,sql server数据库等等其实是 ...

  6. InnoDB的表类型,逻辑存储结构,物理存储结构

    表类型 对比Oracle支持的各种表类型,InnoDB存储引擎表更像是Oracle中的索引组织表(index organized table).在InnoDB存储引擎表中,每张表都有个主键,如果在创建 ...

  7. 第三章(附)mysql表类型MyISAM和InnoDB区别(决定了是否支持事务)

    mysql表类型MyISAM和InnoDB区别 MyISAM:这个是默认类型,它是基于传统的ISAM类型,ISAM是Indexed Sequential Access Method (有索引的顺序访问 ...

  8. MySQL常用的七种表类型(转)

    MySQL常用的七种表类型(转)   其实MySQL提供的表类型截至到今天已经有13种,各有各的好处,但是民间流传的常用的应该是7种,如果再细化出来,基本上就只有两种:InnoDB.MyIASM两种. ...

  9. Oracle12c 性能优化攻略:攻略1-3: 匹配表类型与业务需求

    注:目录表 <Oracle12c 性能优化攻略:攻略目录表> 问题描述 你刚开始使用oracle数据库,并且学习了一些关于可用的各种表类型的知识.例如:可以在堆组织表.索引组织表等之间支出 ...

随机推荐

  1. 1Z0-053 争议题目解析704

    1Z0-053 争议题目解析704 考试科目:1Z0-053 题库版本:V13.02 题库中原题为: 704.View the Exhibit and examine the data manipul ...

  2. spring笔记--通过注解(annotation)配置Bean

    Spring能够在classpath下自动扫描,侦测和实例化具有特定注解的组件,这在Spring中成为组件扫描(Component scanning). 特定组件的注解包括: @Component:基 ...

  3. 五一干货来袭!开源Moon.Orm标准版发布!

    标准版源代码下载: 链接:http://pan.baidu.com/s/1i3xj0f7 因五一早过(现在中旬了),解压码获取请到: http://www.cnblogs.com/humble/p/3 ...

  4. redux+flux(一:入门篇)

    React是facebook推出的js框架,React 本身只涉及UI层,如果搭建大型应用,必须搭配一个前端框架.也就是说,你至少要学两样东西,才能基本满足需要:React + 前端框架. Faceb ...

  5. Effective java笔记(六),方法

    38.检查参数的有效性 绝大多数方法和构造器对于传递给它们的参数值都会有限制.如,对象引用不能为null,数组索引有范围限制等.应该在文档中指明所有这些限制,并在方法的开头处检查参数,以强制施加这些限 ...

  6. Revit读取当前rvt的所有视图与其名称

    1)读取所有视图: public static ViewSet GetAllViews(Document doc) { ViewSet views = new ViewSet(); FilteredE ...

  7. iOS学习笔记——AutoLayout的约束

    iOS学习笔记——AutoLayout约束 之前在开发iOS app时一直以为苹果的布局是绝对布局,在IB中拖拉控件运行或者直接使用代码去调整控件都会发上一些不尽人意的结果,后来发现iOS在引入了Au ...

  8. C#-Socket监听消息处理

    TCP/IP:Transmission Control Protocol/Internet Protocol,传输控制协议/因特网互联协议,又名网络通讯协议.简单来说:TCP控制传输数据,负责发现传输 ...

  9. HDU 5475(2015 ICPC上海站网络赛)--- An easy problem(线段树点修改)

    题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=5475 Problem Description One day, a useless calculato ...

  10. P2P核心业务体系

    看似一个简单的充值.提现按钮,背后可是巨多的逻辑和业务处理.