# 数据库

xnote采用了两种数据库：关系型数据库和NoSQL数据库，两者使用的场景略有不同。下面是我的建议：

使用关系型数据库的理由如下
- 关系型数据库使用起来更简单便捷。
- 关系型数据库有标准的SQL接口，更容易迁移。
- 随着分库分表和`NewSQL`的发展，关系型数据库的性能问题有大量的解决方案。
- 关系型数据库已经广泛支持了`json`格式，对非结构化数据的存储和处理很友好。

使用NoSQL数据库（Redis、Mongodb、Cassandra、ElasticSearch）的理由如下
- 高性能场景，建议使用NoSQL，同样的硬件水平，`redis`可以比`MySQL`的单机QPS高上一个数量级。
- 海量数据存储（亿级以上，并且数据增长很快），建议使用NoSQL，因为NoSQL一般没有中心节点，扩容更方便。
- NoSQL的一些数据结构处理特定问题更加实用（比如`redis`的各种丰富的数据结构）。
- 搜索等对一致性要求不高的场景建议使用NoSQL。

总的来说，NoSQL数据库在一些特定的场景下很好用，其他场景则是关系型数据库的天下。如果你不确定使用哪种数据库，可以先使用关系型数据库。

# 历史

xnote的数据库选型经历了几个阶段
- 第一阶段（v1.0-v2.2）：最开始，xnote是针对个人使用场景进行设计的，所以直接使用了sqlite数据库，长期以来，sqlite一直是应用最为广泛的数据库。
- 第二阶段（v2.3-v2.7）：后面我把xnote部署到了新浪云引擎（SAE），选择了成本比较低的docker部署方案，后面发现sqlite的并发性能随着数据量的增加（几千篇文章）逐渐变差，单个用户操作也经常会出发锁库操作（出现`database is locked`的报错）。原因有两点：
    - sqlite采用的是库锁，读写不能并发，xnote有一些操作是异步的，容易发生并发冲突。
    - SAE采用的是云存储，性能和本地存储相比有较大差异。
    
    所以我重新调研了其他嵌入式数据库，当时我对NoSQL很感兴趣，做了一些性能测试，发现leveldb完全可以胜任我的要求。leveldb的读写是可以同时并发的（写之间不能并发），而且由于API简单，采用了`LSM-Tree`结构，顺序读写性能比sqlite要好很多，通过全表扫描查询的性能都要比sqlite加索引的查询速度快。
- 第三阶段（v2.8-v2.9.3）：leveldb虽然性能好，但是写起来很麻烦，要自己写大量的过滤函数去支持复杂查询。为了解决这个问题，我开发了一套二级索引的函数库，可以使用类似于mongodb的API来实现单表的复杂查询。
- 第四阶段（v2.9.4-Now）：有一些小伙伴也用上了我的系统，每次部署的时候服务会中断，这样体验很不好，所以我需要分离应用服务和存储服务。由于我工作中使用的主要是MySQL，所以这个阶段也逐渐适配到MySQL等传统的关系型存储。