第一章 概述
1.2.1 关系型数据库
Relational DataBase Management System, 实现为具有行和列的二维表。交互标准是SQL。值类型可以是数字,字符串,日期,二进制。mysql,H2,HSOLDB,SQLite,后续主要说PostgreSQL
1.2.2 键值数据库
在一些场景下有令人难以置信的高性能,但是当你有复杂的查询和聚合需求时,它一般不会有帮助。
1.2.3 列型数据库
在面向列的数据库中,添加列是相当容易的,而且是逐行完成的。每一行可以有不同的列,或者完全没有,允许表保持稀疏,而不会产生空值的存储成本。
1.2.4 文档型数据库
文档数据库存储的就是文档。简而言之,文档就是hash,具有独一无二的标识符字段和值,值可能是任何类型,包括更多的hash。文档可以包含嵌套的结构,因此表现出了高度的灵活性,允许有可变域。在建索引,自由定义的查询,复制,一致性及其他设计决策等方面,不同的文档数据库采取了不同的方法。
1.2.5 图数据库
图数据库善于处理高度互联的数据。图数据库包含节点与节点之间的关系。节点和关系可以有一些属性,用来存储数据。图数据库真正实力是按照关系遍历节点。
1.2.6 混合使用多种数据库
第二章 PostgreSQL
关系型数据库流行的原因,不近在于其庞大的特性集(高级索引)、数据的安全性(ACID),或符合大多数人的斯文方式,还在于它们的查询灵活性。
2.1 这就是post-gre-s-q-l
PostgreSQL是历史最悠久,实战经验最丰富的。它的扩展包括自然语言解析、多维索引、地理查询、自定义数据类型等。具有高级的事务能力,支持十几种不同语言的存储过程。PostgreSQL内置支持Unicode、序列、表继承、子查询,快速可靠,可以处理TB级别的数据。
2.2 第一天:关系。CRUD和联接
关系数据库的关系是因为它的数学基础,不是因为它通过外键彼此“关联”。这样的限制是否存在并不关键。
虽然许多数学关系你看不到,但是模型的力量肯定是蕴藏在数学之中。这种魔法允许用户提供功能强大的查询。
2.3.3 窗口函数
在mysql中,如果你试图select一些没有在group by中限定的列,你可能会吃惊的看到,它有结果。这让我们开始怀疑窗口函数的必要性。但更细致的检查mysql返回的数据之后,我们发现它返回的只是一些随机的数据行和计数,并非所有相关的结果。一般来说这是没用的(而且可能相当危险)。
2.4.2 SQL标准的字符串匹配
PostgreSQL有很多方法进行文本匹配,但是两大默认方法是LIKE和正则表达式
- LIKE和ILIKE
select title from moives where title ilike 'stardust%'
有个小技巧,如果想确保子串stardust不在字符串的末尾可以使用下划线(_)字符。
select title from moives where title ilike 'stardust_%'
p.s. 估计现在很少有公司用like吧
- 正则表达式
PostgreSQL采用POSIX风格的正则表达式。在PostgreSQL中,正则表达式的匹配字串由~
运算符开始,还可以带有可选的!
(意思是不匹配)和*
(意思是不区分大小写)。
select count(*) from moives where title !~* '^the.*'
可以为前面查询的模式创建字符串索引,
create index moives_title_pattern on movies(lower(title) text_pattern_ops);
2.4.3 字符串相似比较算法levenshtein
levenshtein是一个字符串比较算法,它能够计算一个字符串需要经过多少步才能变成另一个字符串,从而可能比较两个字符串的相似程度。
select levenshtein('bat','fad') fad,
levenshtein('bat', 'fat') fat,
levenshtein('bat', 'bat') bat
2.4.5 全文检索
- TSVector和TSQuery
查找包含night和day的数据
select title from moives where title @@ 'night&day'
@@
将电影名称转换成tsvector结构体,并将查询转换成tsquery结构体。
select title from moives where to_tsvector(title) @@ to_tsquery('english', 'night&day')
我们来看下向量和查询如何将字符分开
select to_tsvector('A hard day's night), to_tsquery('english', 'night&day')
to_tsvector | to_tsquery |
---|---|
‘day’:3, ‘hard’:2, ‘night’:5 | ‘night’&’day’ |
- 对词素索引
全文检索功能虽然强大。但是如果不创建相关的索引,检索的速度会很慢。explain是个强大的工具,可以查看内部执行计划。当执行计划出现seq scan on table
时基本上都不是什么好现象,我们通过创建反向索引,但是查询同时要指定语言。例如:
select title from moives where to_tsvector('english', title) @@ 'night & day'
- 发音码metaphone
2.5.1 PostgreSQL的优点
2.5.2 PostgreSQL的缺点
PostgreSQL这样的关系数据库,分区不是强项。如果需要水平扩展而不是垂直扩展可能最好寻找其他解决方案。
第三章 Riak(读作Ree-ahck)
Riak是一种分布式的键值数据库。其中值可以是任何类型的数据;而且都能通过http接口访问。容错性是RIak的另一个特性。服务器可在任何时刻启动或者停止,而不会引起任何单点故障。不管是增减或者移除服务器,甚至有节点崩溃,集群依然可以持续忙碌的运行。Riak让你不再整夜无眠担心集群,某个节点失效不再是紧急事件,完全可以等到第二天处理。然而万事都有利弊取舍,Riak的灵活性自有代价,对于自由定义的查询,Riak缺乏有力支持;而键值存储的设计使得数据无法相互连接。
3.1 Riak喜欢web
可以通过URL,HTTP头,HTTP方法查询
3.2 第一天;CRUD、链接和MIME
3.3.4 关于一致性和持久性
将数据分布于多个服务器必须面对一个棘手的先天问题。如果你想要数据库在网络分区发生时依然能够运行,你必须做一个权衡。或者对服务器请求保持可用,或者拒绝请求,以保证数据的一致性。要创建一个具备完全一致性、可用性与分区容错性的分布式数据库,是不可能的。Riak允许在每个请求的基础上,以可用性交换一致性。我们先看Riak如何将服务器组成集群,然后讨论如何调整读写来和集群交互。
Riak环
Riak将其服务器配置划分为分区,以一个160比特的数字表示。把一个键hash为一个分区,这个环会帮忙指向存有响应值的服务器。在搭建一个Riak集群式,遇到的第一个问题就是你想要多少个分区,不妨考虑这样一个案例,你有64个分区(默认)。如果把这64个分区分布在3个节点上,Riak会为每个节点分配21或者22个分区。每个分区为一个虚拟节点,或者vnode。每个Riak服务会在启动时计数,依次清点分区直到所有的vnode都清点完毕。每个vnode代表一系列经过hash的键。当插入键101的客房数据时,它会hash到vnode2的范围,于是键值对象会存储在节点B上。Riak允许通过改变三个值:N,W与R,来控制集群的读写。N是一次写入最终复制到的节点数量,换句话说,就是集群中的副本数量。W是一次成功的写入响应之前,必须成功写入的节点数量。如果W<N,就认为某次写入是成功的,及时Riak依然在复制数据。最后R是成功读出一项数据所必须的节点数量。如果R比可用的复制数量大,读出请求将失败。举个例子:如果N=4,W=2那么在写入两个节点成功之后就会返回成功,后台复制其他节点。这样能更快响应。如果把NRW设置成{“v_val”:3, “r”:2, “w”:1},这种设置使系统写入的操作响应快,但是存在另一种可能,恰巧在节点同步之前,另一个读出操作执行了,那么读到的值可能是错误的。一种确保我们能够读到最新值的方法是让W=N,R=1。从本质上讲,这就是关系型数据库的做法;通过确保写操作在返回之前完成,以保证一致性。但是这确实会降低写操作的性能。或者,可以只写入单点,从而从全部节点读出,让R=N,W=1,尽管你可能因此读到一些旧值,但你也能保证检索到最新的值,这时你需要做的是找出哪些是最新的值。当然这也会带来副作用,读操作会因此减慢。还有一种选择,只需要写入多余一半的节点,并且从多余一半的节点读出,就依然保证了一致性。同时,分担介于读写之间的延时。这成为法定数,是确保数据一致性的方法中开销最小的。
Riak的写入操作未必是持久化的,也就是说并非立即写入磁盘。及时一个节点的写入操作执行成功,依然可能因为故障而丢失,写入磁盘之前,会在内存中缓存片刻,而这毫秒的间隙正是危险的所在。但是Riak提供了名为DW的单独设置,用于持久化写入。但是同样会减慢速度。
关于临时转移,尝试写入不可用的节点仍然会执行成功,并得到这样的返回“204 No content”。这是因为Riak会把数据先写入附近的一个节点,该节点一直保存数据,直到它能将这些数据交给不可用的节点。但是因为一个服务的负载编程双倍导致级联故障,需要注意。
3.4.1 以向量时钟解决冲突
由于若干客户端可能链接到不同的服务器,并且一个客户端更新这个服务器,另一个客户端更新那个服务器,因此记录哪些更新以怎样的顺序发生,是非常重要的。你或许再想“给值加上时间戳,采用时间戳最新的即可”,但是这种做法仅仅在所有节点服务器的时钟完全同步的集群中有效。Riak对此不做要求,事实上,保持时钟同步是最为困难的,在许多情况下,甚至是不可能的。Riak的做法是:对每个键值事件(创建,更新,删除)做标记,标记包含两项内容:哪个客户端更新了数据与以哪种顺序更新。在此基础上,客户端或者应用开发者,需要决定谁在冲突中获胜。如果你熟悉像git或者subversion之类的版本控制,不难发现本质相同。
第四章 Hbase
4.5总结
4.5.1 HBase的优点
Hbase中值得注意的特性包括健壮性的可伸缩架构,以及内置版本和压缩功能。Hbase内置版本功能在某些情况下是强大的特性。在性能方面Hbase意味着可伸缩。如果你有大量的数据,达到很多TB,Hbase可能适合你。Hbase在数据中心的机架内或机架之间复制数据没这样就能优雅而快速的处理节点失效。
4.5.2 Hbase的缺点
Hbase不能缩小,5个节点是你想要的最低配置。文档比较专业,学习曲线更抖。Hbase除了行键之外不提供任何索引功能。Hbase中数据类型都作为字节数组。
4.5.3 Hbase on CAP
Hbase肯定是CP