四、选择

之所以写该节,是因为本文介绍 NeDB,但并不是推荐 NeDB。选取什么样的数据库主要取决于项目以及个人情感。由于涉及到 SQL 数据库与 NoSQL 数据库的概念,所以先从大的方面简单说一下,然后再介绍 Node 嵌入式数据库。

先简单回顾下数据库的分类。

数据库通常分为层次式数据库、网络式数据库和关系式数据库三种。而不同的数据库是按不同的数据结构来联系和组织的。在当今的互联网中,最常见的数据库模型主要有两种:关系型数据库和非关系型数据库。

关系型数据库

关系型数据库模型是把复杂的数据结构归结为简单的二元关系(即二维表格形式)。在关系型数据库中,对数据的操作几乎全部建立在一个或多个关系表格上,通过对这些关联的表格分类、合并、连接或选取等运算来实现数据库的管理。主流关系型数据库有 Oracle、MySQL、MariaDB、SqlServer、Access、PostgreSQL、DB2 等。其中个人感觉 PostgreSQL 功能十分强大,虽是关系型数据库,但支持 json 和 Hstore 字段,兼有事务和文档特性,只是性能就差了点。

非关系型数据库

NoSQL 意味着 Not only SQL。面对超大规模和高并发的 SNS(社交网络服务) 类型的 web2.0 纯动态网站,传统的关系型数据库显得有些力不从心,比如表的横向扩展等。NoSQL 数据库作为传统关系型数据库的有效补充,在特定的场景下可以发挥出难以想象的高效率和高性能。主流的非关系型数据库分为键值存储数据库 (Memcached、Redis 等),列存储数据库 (HBase 等),图形数据库 (Neo4j 等),面向文档数据库 (MongoDB、CouchDB 等)。

由于 NeDB 属于面向文档数据库,这里提及一下该类数据库,了解其它类型数据库可以自行查询官方文档。面向文档数据库可以看做是键值数据库的一个升级,不但允许键值嵌套,还提高了查询效率。面向文档数据库会将数据以文档形式存储。每个文档都是自包含的数据单元,是一系列数据项的集合。每个数据项都有一个名词与对应值,值既可以是简单的数据类型,如字符串、数字和日期等;也可以是复杂的类型,如有序列表和关联对象。数据存储的最小单位是文档,同一个表中存储的文档属性可以是不同的,数据可以使用 XML、JSON 或 JSONB 等多种形式存储。

介绍完分类,接下来就简单说一下各自的使用场景。

RDBMS

特点:

  • 提供事务,使两个或两个以上的成功或失败的数据更改作为一个原子单元;
  • 高度组织化结构化数据;
  • 数据和关系都存储在单独的表中;
  • 需要预先定义表模式;
  • 鼓励标准化减少数据冗余;
  • 支持多表查询;
  • 强制数据完整性;
  • 严格的一致性;
  • 支持扩展(横向扩展有些痛苦);
  • 结构化查询语言(SQL);
  • 诞生 40 年之多,十分成熟,有足够的支持;

从其特点分析,可看出其适合有明确的定义,规范比较明确的项目。比如在线商城和银行系统等。该类系统需要具备强制数据完整性以及事务支持的健壮存储系统。可以试想一下如果去 ATM 机取钱,ATM 机没有吐钱,但是后台数据库已经把钱减掉了,会是一种什么样的体验呢?

NoSQL

特点:

  • Not only SQL;
  • 没有声明性查询语言;
  • 没有预定义的模式;
  • 键-值对存储,列存储,文档存储,图形数据库;
  • 最终一致性,而非 ACID 属性;
  • 非结构化和不可预知的数据;
  • CAP 定理 ;
  • 高性能,高可用性和可伸缩性;
  • 是一个新的、令人兴奋的技术,并不是十分成熟;

从其特点分析,最适合无固定要求的组织数据。比如社交网络、客户管理和网络监控系统等。

就客户管理系统来说,假如刚开始使用关系型数据库建一个联系人的表,表字段有主键 id、姓名 name、电话 telephone、邮箱 email、地址 address。那么问题来了,现在有联系人有三个电话号码(住宅座机、移动电话、工作电话)需要输入,这时就要考虑单独创建一个 telephone 表,这样就不受限制了,也让我们的数据标准化了。新建 telephone 表结构:联系人 contact_id、号码类型 name、号码 num。email 与 address 也存在同样的问题,address 的情况更加复杂,这里不再展开。对关系型数据库来说,Schema 是固定不变的,而我们事先是不能预测所有字段的,比如刚才的联系人表,很快我们会发现当前字段不能满足,比如要添加性别 gender、年龄 age、生日 birthday 等字段,那么最后就导致需要加一个 otherdata 表。数据又是碎片化的,当查询一个联系人时,如果该联系人有 3 个电话号码、2 个 email 地址和 5 个地址,那么 SQL 查询需要检查所有表,并将产生 325=30 条结果,使得全文搜索很困难。

面对这种情况,如果选择 NoSQL 数据库,联系人列表将从中受益。数据库将一个联系人的所有数据存储在一个单独的文档里的 contacts 集合里。

  1. [
  2. {
  3. name:"tom",
  4. telephone:{
  5. home:"123456",
  6. mobile:"123456789",
  7. work:"1234567890"
  8. },
  9. ...
  10. },
  11. ...
  12. ]

如果这时需要添加一些数据,这些数据没有必要应用到之前的联系人,NoSQL 数据库就可以随意添加或移除字段。联系人数据存储在单独的文档中,也使得全文搜索变得简单。

介绍完 SQL 与 NoSQL 数据库的基本概念,就该回到正题啦,介绍下 Node 嵌入式数据库,SQLite 同样也有 SQL 与 NoSQL 之分。

Nodejs 可用的 SQLite 有 node-sqlite,node-sqlite3,NeDB,nStore 以及 final-db 等。其中 node-sqlite,node-sqlite3 属于 SQL 数据库,NeDB,nStore 以及 final-db 属于 NoSQL 数据库。如需详细了解各个模块,可以去看相应的官方文档。

其中使用最多的应该算 node-sqlite3 和 NeDB 了,两者的区别很明显,前者是 SQL 数据库,后者是 NoSQL 数据库。另外,sqlite3 相对 NeDB 要重一些,性能也要差一点,使用 SQL 语句失去了 js 直接操作 json 的简便,API 也相对复杂很多。而 NeDB 只提供了基本的 CURD 操作,只能用于小型应用,大场景并不适用,数据加载到内存中进行操作,不适合内存非常紧张的应用,目前作者也没有给出具体的内存控制方法。。