在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. C#运用GmaQrCode生成二维码

    项目中需要生成二维码,方法比较多,可以采用JS插件,也可以采用第三方插件后台生成二维码,在后台方法中可以采用QRCode或者GmaQrCode,现在介绍一种C#在后台生成二维码的方法: /// < ...

  2. CSS实现的手风琴特效

    CSS样式: //图像个数 @imageN:5; //图像hover之前的总宽度 @w:800px; //图像hover之后的宽度 @imageL:640px; //图像hover之前的宽度 @ima ...

  3. 汽车之家一道SQL 面试题,大家闲来无事都来敲一敲

    写在前面 上周去汽车之家面试,拿到这个SQL笔试题顿时感觉到有些陌生,因为好长时间不写SQL语句了,当时只写了表设计,示例数据和SQL语句都没写出来. 汽车之家应该用的SQL Server, 编程题一 ...

  4. 2.第一个Struts2程序-HelloWorld程序

    1.新建Web Project项目:Study_Struts2 2.新建HelloWordAction.java类 3.复制struts.xml文件到src目录下,配置struts.xml文件内容如下 ...

  5. Win 10 UWP开发系列:设置AppBarButton的图标

    在WP8以前,页面最下面的四个小圆按钮是不支持绑定的,WP8.1 RT之后,系统按钮升级成了AppBarButton,并且支持绑定了.在Win10 UWP开发中,按钮的样式发生了变化,外面的圆圈没有了 ...

  6. c#自定义日志记录

    废话不多说,直接上代码: 很简单:将类复制到项目中,最后在配置文件上配置一下:logUrl即可. 默认保存在:项目/temp/log /// <summary> /// 日志类 /// & ...

  7. 【C#进阶系列】29 混合线程同步构造

    上一章讲了基元线程同步构造,而其它的线程同步构造都是基于这些基元线程同步构造的,并且一般都合并了用户模式和内核模式构造,我们称之为混合线程同步构造. 在没有线程竞争时,混合线程提供了基于用户模式构造所 ...

  8. 把生成的excel文件直接提供为下载页效果

    把php中的excel显示下载页下载到本地硬盘需要设置头信息: 代码: $objWriter = \PHPExcel_IOFactory::createWriter($objPHPExcel, 'Ex ...

  9. js 强转规范解读

    js的强转是我们很容易遇到坑的一个地方 比如 == 会产生很有意思的事情(使用===还是最佳实践的)  或者+new Date()一个当前的数字时间戳  这里面都涉及到强转  下面分享下学习强转的过程 ...

  10. SharePoint 2013 入门教程之创建及修改母版页

    在SharePoint 2013中,微软提供了根据HTML页面转换Master页的方法,并支持单项同步,但是这样的更新,并不完善,会使一些功能造成丢失,所以,了解Master结构的人,尽量直接去修改M ...