一些数据库学习的小结:
SQL: 遵循ACID原则。优点是1)支持Transaction。2) 支持JOIN。缺点是高并发比较弱,scalability弱。适合在线交易处理(OLTP),不适合在线分析处理(OLAP),也有说适合OLAP的。例子有
MySQL 读写效率 单机约1KQPS
POSTGRESQL
SQL Server
Oracle
NoSQL: 遵循BASE原则。各有优势。通常效率高。缺点是1)不支持Transaction; 2)JOIN操作效率不高; 3)占用空间大。例子有
DynamoDB - Amazon Key-Value
BigTable - Google
MongoDB - 读写效率 单机约10QPS
Cassandra - 读写效率 单机约10QPS
Redis - 内存数据库 Key-Value 读写效率 单机约100KQPS。注意:Redis的设计是用来做缓存的,它是一个内存数据库,不过因为其某些特性适合用来充当队列(Redis的List数据结构比较适合做MQ),所以也多被用于做简单的消息队列。
Memcached - 内存数据库 单机约1MQPS ?
NoSQL 有四种类型
- Document Stores: Document以JSON,XML, PDF或OFFICE Document等格式存储,称为BLOB。数据模型为一对多的树状结构。没有Schema,可以随意地存储与读取数据,因此文档型NoSql的出现是解决关系型数据库表结构扩展不方便的问题的。例子有MongoDB(完全和关系型数据库对标,数据用JSON存储), CouchDB, RethinkDB, Espresso。
- Graph Databases: Neo4j, VertexDB,还有Facebook的大数据图数据库TAO (适合存社交图谱)。
- Key-Value Stores: Key存在Hash-table里面。支持通常的CRUD操作,不支持JOIN和AGGREATE操作 (因为Hash函数不支持Range Query的操作)。键值数据库主要运行在内存,实现定期向硬盘读写数据的策略。例子有Redis, Memcached, Riak(是DynamoDB的开源实现), DynamoDB, LevelDB, RocksDB。
- Columnar Databases: 适合在线分析处理(OLAP),不适合在线交易处理(OLTP)。采用列式存储? 适合Range Query? 例子有MariaDB, Cassandra (开源), HBase(BigTable的实现), Vertica。
列式存储1)节约空间,Null值不会被存储,一列中有时候会有很多重复数据(尤其是枚举数据,性别、状态等),这类数据可压缩,行式数据库压缩率通常在3:1 ~ 5:1之间,列式数据库的压缩率一般在8:1~30:1左右。2) 列数据被组织到一起,一次磁盘IO可以将一列数据一次性读取到内存中。性能高。
我再加上第五种类型:
搜索型NoSql: 采用倒排索引。例子有ElasticSearch,适合文本查询。缺点是耗内存,因为是基于KV查询。必须全部装入内存?
关于SQL和NoSQL的选择
下面内容来自 https://www.cnblogs.com/xrq730/p/11039384.html
重点考虑两点:
- 数据间是否有一致性的要求?
- 是否核心数据且有多字段组合查询场景?
第一点,不多解释应该都理解,非关系型数据库都是通过牺牲了ACID特性来获取更高的性能的,假设两张表之间有比较强的一致性需求,那么这类数据是不适合放在非关系型数据库中的。
第二点,核心数据不走非关系型数据库,例如用户表、订单表,但是这有一个前提,就是这一类核心数据会有多种查询模式,例如用户表有ABCD四个字段,可能根据AB查,可能根据AC查,可能根据D查,假设核心数据,但是就是个KV形式,比如用户的聊天记录,那么HBase一存就完事了。
非核心数据尤其是日志、流水一类中间数据千万不要写在关系型数据库中,这一类数据通常有两个特点:
写远高于读
写入量巨大
一旦使用关系型数据库作为存储引擎,将大大降低关系型数据库的能力,正常读写QPS不高的核心服务会受这一类数据读写的拖累。
关于NoSQL的选型
选型要结合实际情况而不是照本宣科,比如:
- 企业发展之初,明明一个关系型数据库就能搞定且支撑一年的架构,搞一套大而全的技术方案出来。
- 有一些数据条件查询多,更适合使用ElasticSearch做存储降低关系型数据库压力,但是公司成本有限,这种情况下这类数据可以尝试继续使用关系型数据库做存储。
- 有一类数据格式简单,就是个KV类型且增长量大,但是公司没有HBase这方面的人才,运维上可能会有一定难度,出于实际情况考虑,可先用关系型数据库顶一阵子。
所以,如果不考虑实际情况,虽然合适有些存储引擎更加合适,但是强行使用反而适得其反,总而言之,适合自己的才是最好的。
下面这些帖子讲的不错。
https://devpress.csdn.net/awstech/64e730eaa3cccc782cc5672e.html?dp_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6MTI0ODc4MCwiZXhwIjoxNzAxNDE5Mjk3LCJpYXQiOjE3MDA4MTQ0OTcsInVzZXJuYW1lIjoicm91Zm9vIn0.OEngDhSlFpKn1WbVxkceyS8kl3lY3KBG7Qk5U_LVGG8
https://www.sohu.com/a/348809104_315839
https://www.cnblogs.com/xrq730/p/11039384.html
关于数据模型
one-to-many 适合tree状结构,可以用document model
many-to-many 可以用relational model,最好用graph model
关于索引
MySQL - 基于B+树
MongoDB - 基于B树
B-Tree 和 LSM-Tree对比:
- B-Tree读快,LSM-Tree写快。
- B-Tree不适合压缩,LSM-Tree适合压缩
B-Tree的缺点有: - B-Tree不适合压缩
- B-Tree会产生更多的磁盘碎片,LSM-Tree的磁盘碎片少。
- B-Tree会产生更多的写放大,LSM-Tree的写放大通常小一些。
B-Tree的优点有: - 每个key在索引里面只存储一次,可以更好的支持Transaction。
LSM-Tree的缺点有: - Compact过程会影响读写性能。
- 数据库越大,更多的磁盘带宽要分配给Compact过程而不是initial write (logging and flushing a memtable to disk)
关于存储引擎
有两大类storage engines: log-structured store engine and page-oriented storage engines such as B-trees.
log-structured store engine: 也叫LSM storage engine. 例子有LevelDB, RocksDB, HBase, Cassandra
page-oriented storage engines:
关于Isolation Level
- Serializable - 最高级别
- Repeatable reads - 就是Snapshot Isolation ?
- transaction看到的数据是该transaction刚开始的时候所看到的committed的数据。写要加锁,读不用加锁,读snapshot就可以了。通过MVCC实现。
- Read Committed - 最基本的级别
- dirty read 读到还没有committed的数据。 dirty write 是overwrite还没有committed的数据。
- 防止dirty read和dirty write, 可以通过加锁实现。但较长的写操作会使得其它transaction等很长时间。所以很多数据库会记住旧的committed的数据和新的transaction正在写的数据(write lock hold)。如果有其它transaction来读这个数据,则返回旧的committed的数据。只有当新数据committed之后,其它transactions才能读到新的数据。
- 通常Read Committed 每次query都用一个单独的snapshot,而Snapshot Isolation整个transaction期间都用同一个snapshot。
- Read Uncommitted - 最低级别
5
个人一些总结:
- 列式存储在Range Query上有优势,所以很适合OLAP。
- LSM树适合压缩(bit-wise + run-length编码)和Update(写)。
- 倒排索引适合模糊查找。
- 关于ACID。
Atomicity - 用WAL 实现,也可用通过compare-and-set之类的原子操作实现。
Consistency - 其实是4个里面最重要的。其它3个都是为它服务。
Isolation - 用Lock实现
Durability
一些英汉对应:
复合索引 composite index
倒排索引 inverted index
列式存储 columnar or column-based