非关系型数据库

更新时间:2023-07-08 14:36:06 阅读: 评论:0

目录
非关系型数据库的特点    1
1.关系型数据库    1
2. 关系型数据库瓶颈    2
3. NoSQL    2
4. 关系型数据库与非关系型数据库的区别    2
非关系型数据库简介    3
SQLite    3
Redis    3
Tokyo Cabinet和Tokoy Tyrant    9
MongoDB    9
CouchDB    10
Cassandra    10
Voldemort    10
LevelDB    10
非关系型数据库的特点
1.关系型数据库
关系型数据库,是指采用了关系模型来组织数据的数据库。
简单来说,关系模型指的就是二维表格模型,而一个关系型数据库就是由二维表及其之间的联系所组成的一个数据组织。
关系模型中常用的概念:
关系:可以理解为一张二维表,每个关系都具有一个关系名,就是通常说的表名
元组:可以理解为二维表中的一行,在数据库中经常被称为记录
属性:可以理解为二维表中的一列,在数据库中经常被称为字段
域:属性的取值范围,也就是数据库中某一列的取值限制
关键字:一组可以唯一标识元组的属性,数据库中常称为主键,由一个或多个列组成
关系模式:指对关系的描述。其格式为:关系名(属性1,属性2, ... ... ,属性N),在数据库中成为表结构
关系型数据库的优点:
容易理解:二维表结构是非常贴近逻辑世界的一个概念,关系模型相对网状、层次等其他模型来说更容易理解
使用方便:通用的SQL语言使得操作关系型数据库非常方便
易于维护:丰富的完整性(实体完整性、参照完整性和用户定义的完整性)大大减低了数据冗余和数据不一致的概率
2. 关系型数据库瓶颈
高并发读写需求
网站的用户并发性非常高,往往达到每秒上万次读写请求,对于传统关系型数据库来说,硬盘I/O是一个很大的瓶颈
海量数据的高效率读写
化学自习室
网站每天产生的数据量是巨大的,对于关系型数据库来说,在一张包含海量数据的表中查询,效率是非常低的
手机恢复数据高扩展性和可用性
在基于web的结构当中,数据库是最难进行横向扩展的,当一个应用系统的用户量和访问量与日俱增的时候,数据库却没有办法像web rver和app rver那样简单的通过添加更多的硬件和服务节点来扩展性能和负载能力。对于很多需要提供24小时不间断服务的网站来说,对数据库系统进行升级和扩展是非常痛苦的事情,往往需要停机维护和数据迁移。
对网站来说,关系型数据库的很多特性不再需要了:
事务一致性
关系型数据库在对事物一致性的维护中有很大的开销,而现在很多web2.0系统对事物的读写一致性都不高
读写实时性
对关系数据库来说,插入一条数据之后立刻查询,是肯定可以读出这条数据的,但是对于很多web应用来说,并不要求这么高的实时性,比如发一条消息之后,过几秒乃至十几秒之后才看到这条动态是完全可以接受的
复杂SQL,特别是多表关联查询
生气的英文任何大数据量的web系统,都非常忌讳多个大表的关联查询,以及复杂的数据分析类型的复杂SQL报表查询,特别是SNS类型的网站,从需求以及产品阶级角度,就避免了这种情况的产生。往往更多的只是单表的主键查询,以及单表的简单条件分页查询,SQL的功能极大的弱化了
在关系型数据库中,导致性能欠佳的最主要原因是多表的关联查询,以及复杂的数据分析类型的复杂SQL报表查询。为了保证数据库的ACID特性,我们必须尽量按照其要求的范式进行设计,关系型数据库中的表都是存储一个格式化的数据结构。每个元组字段的组成都是一样,即使不是每个元组都需要所有的字段,但数据库会为每个元组分配所有的字段,这样的结构可以便于标语表之间进行链接等操作,但从另一个角度来说它也是关系型数据库性能瓶颈的一个因素。
3. NoSQL
2009年初,Johan Oskarsson举办了一场关于开源分布式数据库的讨论,Eric Evans在这次讨论中提出了NoSQL一词,用于指代那些非关系型的,分布式的,且一般不保证遵循ACID原则的数据存储系统。Eric Evans使用NoSQL这个词,并不是因为字面上的“没有SQL”的意思,他只是觉得很多经典的关系型数据库名字都叫“**SQL”,所以为了表示跟这些关系型数据库在定位上的截然不同,就是用了“NoSQL“一词。
注:数据库事务必须具备ACID特性,ACID是Atomic原子性,Consistency一致性,Isolation隔离性,Durability持久性。
非关系型数据库提出另一种理念,例如,以键值对存储,且结构不固定,每一个元组可以有不一样的字段,每个元组可以根据需要增加一些自己的键值对,这样就不会局限于固定的结构,可以减少一些时间和空间的开销。使用这种方式,用户可以根据需要去添加自己需要的字段,这样,为了获取用户的不同信息,不需要像关系型数据库中,要对多表进行关联查询。仅需要根据id取出相应的value就可以完成查询。但非关系型数据库由于很少的约束,他也不能够提供像SQL所提供的where这种对于字段属性值情况的查询。并且难以体现设计的完整性。他只适合存储一些较为简单的数据,对于需要进行较复杂查询的数据,SQL数据库显的更为合适。
4. 关系型数据库与非关系型数据库的区别
关系型数据库的最大特点就是事务的一致性:传统的关系型数据库读写操作都是事务的,具有ACID的特点,这个特性使得关系型数据库可以用于几乎所有对一致性有要求的系统中,如典型的银行系统。
但是,在网页应用中,尤其是SNS应用中,一致性却不是显得那么重要,用户A看到的内容和用户B看到同一用户C内容更新不一致是可以容忍的,或者说,两个人看到同一好友的
数据更新的时间差那么几秒是可以容忍的,因此,关系型数据库的最大特点在这里已经无用武之地,起码不是那么重要了。
相反地,关系型数据库为了维护一致性所付出的巨大代价就是其读写性能比较差,而像微博、facebook这类SNS的应用,对并发读写能力要求极高,关系型数据库已经无法应付(在读方面,传统上为了克服关系型数据库缺陷,提高性能,都是增加一级memcache来静态化网页,而在SNS中,变化太快,memchache已经无能为力了),因此,必须用新的一种数据结构存储来代替关系数据库。
关系数据库的另一个特点就是其具有固定的表结构,因此,其扩展性极差,而在SNS中,系统的升级,功能的增加,往往意味着数据结构巨大变动,这一点关系型数据库也难以应付,需要新的结构化数据存储。
于是,非关系型数据库应运而生,由于不可能用一种数据结构化存储应付所有的新的需求,因此,非关系型数据库严格上不是一种数据库,应该是一种数据结构化存储方法的集合。
必须强调的是,数据的持久存储,尤其是海量数据的持久存储,还是需要一种关系数据库
非关系型数据库简介
SQLite
1. ACID事务
2. 零配置 – 无需安装和管理配置
3. 储存在单一磁盘文件中的一个完整的数据库
4. 数据库文件可以在不同字节顺序的机器间自由的共享
5. 支持数据库大小至2TB
6. 足够小, 大致3万行C代码, 250K
7. 比一些流行的数据库在大部分普通数据库操作要快
8. 简单, 轻松的API
9. 包含TCL绑定, 同时通过Wrapper支持其他语言的绑定
10. 良好注释的源代码, 并且有着90%以上的测试覆盖率
11. 独立: 没有额外依赖
12. Source完全的Open, 你可以用于任何用途, 包括出售它
13. 支持多种开发语言,C, PHP, Perl, Java, ASP ,Python
Redis
Redis是一个很新的项目。Redis本质上是一个Key-Value类型的内存数据库,很像memcached,整个数据库统加载在内存当中进行操作,定期通过异步操作把数据库数据flush到硬盘上进行保存。因为是纯内存操作,Redis的性能非常出色,每秒可以处理超过 10万次读写操作。Redis的出色之处不仅仅是性能,Redis最大的魅力是支持保存List链表和Set集合的数据结构,而且还支持对List进行各种操作,它的值可以是string,list,ts,或者是ordered ts。例如从List两端push和pop数据,取List区间,排序等等,对Set支持各种集合的并集交集操作,此外单个value的最大限制是1GB,不像memcached只能保存1MB的数据,因此Redis可以用来实现很多有用的功能,比方说用他的List来做FIFO双向链表,实现一个轻量级的高性能消息队列服务,用他的Set可以做高性能的tag系统等等。另外Redis也可以对存入的Key-Value设置expire时间,因此也可以被当作一个功能加强版的memcached来用。
Redis的主要缺点是数据库容量受到物理内存的限制,不能用作海量数据的高性能读写,并且它没有原生的可扩展机制,不具有scale(可扩展)能力,要依赖客户端来实现分布式读写,因此Redis适合的场景主要局限在较小数据量的高性能操作和运算上。根据Redis的官网测试报告,50个并发请求,10w次访问,写速度为11x10e4/s,读速度为8100次/s.目前使用Redis的网站有github,Engine Yard。
redis支持的各种数据类型包括string,list ,t ,sorted t 和hash
 
1. keys
redis本质上一个key-value db,所以我们首先来看看他的key.首先key也是字符串类型,但是key中不能包括边界字符
由于key不是binary safe的字符串,所以像"my key"和"mykey\n"这样包含空格和换行的key是不允许的
顺便说一下在redis内部并不限制使用binary字符,这是redis协议限制的。"\r\n"在协议格式中会作为特殊字符。
redis 1.2以后的协议中部分命令已经开始使用新的协议格式了(比如MSET)。总之目前还是把包含边界字符当成非法的key吧,
免得被bug纠缠。
  另外关于key的一个格式约定介绍下,object-type:id:field。比如ur:1000:password,blog:xxidxx:title
还有key的长度最好不要太长。道理很明显占内存啊,而且查找时候相对短key也更慢。不过也推荐过短的key,
比如u:1000:pwd,这样的。显然没上面的ur:1000:password可读性好。

下面介绍下key相关的命令
exits key 测试指定key是否存在,返回1表示存在,0不存在
del key1 key2 ....keyN  删除给定key,返回删除key的数目,0表示给定key都不存在
type key 返回给定key的value类型。返回 none 表示不存在key,string字符类型,list 链表类型 t 无序集合类型...
keys pattern 返回匹配指定模式的所有key,下面给个例子
redis> t test dsf
OK
redis> t tastdsaf
OK
redis> t tistadff
OK
redis> keys t*
1. "tist"
2. "tast"
3. "test"
redis> keys t[ia]st
1. "tist"
2. "tast"
redis> keys t?st
1. "tist"
2. "tast"谷歌图书馆
3. "test"

randomkey返回从当前数据库中随机选择的一个key,如果当前数据库是空的,返回空串 
rename oldkeynewkey原子的重命名一个key,如果newkey存在,将会被覆盖,返回1表示成功,0失败。可能是oldkey不存在或者和newkey相同
renamenxoldkeynewkey同上,但是如果newkey存在返回失败
dbsize返回当前数据库的key数量
expire key conds 为key指定过期时间,单位是秒。返回1成功,0表示key已经设置过过期时间或者不存在
ttl key 返回设置过过期时间的key的剩余过期秒数 -1表示key不存在或者没有设置过过期时间
lect db-index 通过索引选择数据库,默认连接的数据库所有是0,默认数据库数是16个。返回1表示成功,0失败
move key db-index  将key从当前数据库移动到指定数据库。返回1成功。0 如果key不存在,
或者已经在指定数据库中
flushdb删除当前数据库中所有key,此方法不会失败。慎用
flushall删除所有数据库中的所有key,此方法不会失败。更加慎用

2. string 类型
string是redis最基本的类型,而且string类型是二进制安全的。意思是redis的string可以包含任何数据。比如jpg图片或者序列化的对象
。从内部实现来看其实string可以看作byte数组,最大上限是1G字节。下面是string类型的定义。
structsdshdr {
    long len;
    long free;
    char buf[];
};
buf是个char数组用于存贮实际的字符串内容。其实char和c#中的byte是等价的,都是一个
字节
len是buf数组的长度,free是数组中剩余可用字节数。由此可以理解为什么string类型是二进制安全的了。因为它本质上就是个byte数组。
当然可以包含任何数据了。另外string类型可以被部分命令按int处理.比如incr等命令,下面详细介绍。还有redis的其他类型像list,t,sorted t ,hash
它们包含的元素与都只能是string类型。
如果只用string类型,redis就可以被看作加上持久化特性的memcached.当然redis对string类型的操作比memcached多很多啊。如下:

t key value 设置key对应的值为string类型的value,返回1表示成功,0失败
tnx key value 同上,如果key已经存在,返回0 。nx是not exist的意思
get key 获取key对应的string值,如果key不存在返回nil
gett key value 原子的设置key的值,并返回key的旧值。如果key不存在返回nil
昨夜见军帖mget key1 key2 ... keyN一次获取多个key的值,如果对应key不存在,则对应返回nil。下面是个实验,首先清空当前数据库,然后
设置k1,k2.获取时k3对应返回nil
redis>flushdb
OK
redis>dbsize
(integer) 0
redis> t k1 a
OK
辣白菜炖五花肉redis> t k2 b
OK
redis>mget k1 k2 k3
1. "a"
2. "b"
3. (nil)

mt key1 value1 ... keyNvalueN一次设置多个key的值,成功返回1表示所有的值都设置
了,失败返回0表示没有任何值被设置
mtnx key1 value1 ... keyNvalueN同上,但是不会覆盖已经存在的key
incr key 对key的值做加加操作,并返回新的值。注意incr一个不是int的value会返回错误,incr一个不存在的key,则设置key为1
decr key 同上,但是做的是减减操作,decr一个不存在key,则设置key为-1
incrby key integer 同incr,加指定值,key不存在时候会设置key,并认为原来的value是 0
decrby key integer 同decr,减指定值。decrby完全是为了可读性,我们完全可以通过incrby一个负值来实现同样效果,反之一样。

append key value  给指定key的字符串值追加value,返回新字符串值的长度。下面给个例子
redis> t k hello
OK
redis> append k ,world
(integer) 11
redis> get k
"hello,world"

substr key start end 返回截取过的key的字符串值,注意并不修改key的值。下标是从0开始的,接着上面例子
redis>substr k 0 8
"hello,wor"
redis> get k晚上睡不着是什么原因
"hello,world"

3. list

redis的list类型其实就是一个每个子元素都是string类型的双向链表。所以[lr]push和[lr]pop命令的算法时间复杂度都是O(1)
另外list会记录链表的长度。所以llen操作也是O(1).链表的最大长度是(2的32次方-1)。我们
可以通过push,pop操作从链表的头部
或者尾部添加删除元素。这使得list既可以用作栈,也可以用作队列。有意思的是list的pop操作还有阻塞版本的。当我们[lr]pop一个
list对象是,如果list是空,或者不存在,会立即返回nil。但是阻塞版本的b[lr]pop可以则可以阻塞,当然可以加超时时间,超时后也会返回nil
南开大学就业。为什么要阻塞版本的pop呢,主要是为了避免轮询。举个简单的例子如果我们用list来实现一个工作队列。执行任务的thread可以调用阻塞版本的pop去
获取任务这样就可以避免轮询去检查是否有任务存在。当任务来时候工作线程可以立即返回,也可以避免轮询带来的延迟。ok下面介绍list相关命令

lpush key string 在key对应list的头部添加字符串元素,返回1表示成功,0表示key存在且不是list类型
rpush key string 同上,在尾部添加
llen key 返回key对应list的长度,key不存在返回0,如果key对应类型不是list返回错误
lrange key start end 返回指定区间内的元素,下标从0开始,负值表示从后面计算,-1表示
倒数第一个元素,key不存在返回空列表
ltrim key start end  截取list,保留指定区间内元素,成功返回1,key不存在返回错误
lt key index value 设置list中指定下标的元素值,成功返回1,key或者下标不存在返回错误
lrem key count value 从key对应list中删除count个和value相同的元素。count为0时候删除全部
lpop key 从list的头部删除元素,并返回删除元素。如果key对应list不存在或者是空返回nil,如果key对应值不是list返回错误
rpop同上,但是从尾部删除
keyN timeout 从左到右扫描返回对第一个非空list进行lpop操作并返回,比如blpop list1 list2 list3 0 ,如果list不存在
list2,list3都是非空则对list2做lpop并返回从list2中删除的元素。如果所有的list都是空或不存在,则会阻塞timeout秒,timeout为0表示一直阻塞。
当阻塞时,如果有client对keyN中的任意key进行push操作,则第一在这个key上被阻塞的client会立即返回。如果超时发生,则返回nil。有点像unix的lect或者poll
brpop同blpop,一个是从头部删除一个是从尾部删除

rpoplpushsrckeydestkey从srckey对应list的尾部移除元素并添加到destkey对应list的头部,最后返回被移除的元素值,整个操作是原子的.如果srckey是空
或者不存在返回nil

4. t
 redis的t是string类型的无序集合。t元素最大可以包含(2的32次方-1)个元素。t的是通过hash table实现的,所以添加,删除,查找的复杂度都是O(1)。hash table会随着添加或者删除自动的调整大小。需要注意的是调整hash table大小时候需要同步(获取写锁)会阻塞其他读写操作。可能不久后就会改用跳表(skip list)来实现
跳表已经在sorted t中使用了。关于t集合类型除了基本的添加删除操作,其他有用的操作还包含集合的取并集(union),交集(interction),
差集(difference)。通过这些操作可以很容易的实现sns中的好友推荐和blog的tag功能。下面详细介绍t相关命令


sadd key member 添加一个string元素到,key对应的t集合中,成功返回1,如果元素以及在集合中返回0,key对应的t不存在返回错误
srem key member 从key对应t中移除给定元素,成功返回1,如果member在集合中不存在或者key不存在返回0,如果key对应的不是t类型的值返回错误
spop key 删除并返回key对应t中随机的一个元素,如果t是空或者key不存在返回nil
srandmember key 同spop,随机取t中的一个元素,但是不删除元素
smovesrckeydstkey member 从srckey对应t中移除member并添加到dstkey对应t中,整个操作是原子的。成功返回1,如果member在srckey中不存在返回0,如果
key不是t类型返回错误
scard key 返回t的元素个数,如果t是空或者key不存在返回0
sismember key member 判断member是否在t中,存在返回1,0表示不存在或者key不存在
sinter keyN返回所有给定key的交集
keyN同sinter,但是会同时将交集存到dstkey下
sunion keyN返回所有给定key的并集
keyN同sunion,并同时保存并集到dstkey下
sdiff keyN返回所有给定key的差集
keyN同sdiff,并同时保存差集到dstkey下
smembers key 返回key对应t的所有元素,结果是无序的

5 sorted t
和t一样sorted t也是string类型元素的集合,不同的是每个元素都会关联一个double类型的score。sorted t的实现是skip list和hash table的混合体
当元素被添加到集合中时,一个元素到score的映射被添加到hash table中,所以给定一个元素获取score的开销是O(1),另一个score到元素的映射被添加到skip list
并按照score排序,所以就可以有序的获取集合中的元素。添加,删除操作开销都是O(log(N))和skip list的开销一致,redis的skip list实现用的是双向链表,这样就
可以逆序从尾部取元素。sorted t最经常的使用方式应该是作为索引来使用.我们可以把要排序的字段作为score存储,对象的id当元素存储。下面是sorted t相关命令


zadd key score member 添加元素到集合,元素在集合中存在则更新对应score
zrem key member 删除指定元素,1表示成功,如果元素不存在返回0
zincrby key incr member 增加对应member的score值,然后移动元素并保持skip list保持有序。返回更新后的score值
zrank key member 返回指定元素在集合中的排名(下标),集合中元素是按score从小到大排序的
zrevrank key member 同上,但是集合中元素是按score从大到小排序
zrange key start end 类似lrange操作从集合中去指定区间的元素。返回的是有序结果
zrevrange key start end 同上,返回结果是按score逆序的
zrangebyscore key min max 返回集合中score在给定区间的元素
zcount key min max 返回集合中score在给定区间的数量
zcard key 返回集合中元素个数
zscore key element  返回给定元素对应的score
zremrangebyrank key min max 删除集合中排名在给定区间的元素
zremrangebyscore key min max 删除集合中score在给定区间的元素

6. hash 
redis hash是一个string类型的field和value的映射表.它的添加,删除操作都是O(1)(平均).hash特别适合用于存储对象。相较于将对象的每个字段存成
单个string类型。将一个对象存储在hash类型中会占用更少的内存,并且可以更方便的存取整个对象。省内存的原因是新建一个hash对象时开始是用zipmap(又称为small hash)来存储的。这个zipmap其实并不是hash table,但是zipmap相比正常的hash实现可以节省不少hash本身需要的一些元数据存储开销。尽管zipmap的添加,删除,查找都是O(n),但是由于一般对象的field数量都不太多。所以使用zipmap也是很快的,也就是说添加删除平均还是O(1)。如果field或者value的大小超出一定限制后,redis会在内部自动将zipmap替换成正常的hash实现. 这个限制可以在配置文件中指定

本文发布于:2023-07-08 14:36:06,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/82/1085655.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:数据库   关系   返回   元素   数据
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图