丰富的数据结构使得redis的设计非常的有趣。不像关系型数据库那样,DEV和DBA需要深度沟通,review每行sql语句,也不像memcached那样,不需要DBA的参与。redis的DBA需要熟悉数据结构,并能了解使用场景。
下面举一些常见适合kv数据库的例子来谈谈键值的设计,并与关系型数据库做一个对比,发现关系型的不足之处。
用户登录系统
记录用户登录信息的一个系统, 我们简化业务后只留下一张表。
关系型数据库的设计
mysql> select * from login; +---------+----------------+-------------+---------------------+ | user_id | name | login_times | last_login_time | +---------+----------------+-------------+---------------------+ | 1 | ken thompson | 5 | 2011-01-01 00:00:00 | | 2 | dennis ritchie | 1 | 2011-02-01 00:00:00 | | 3 | Joe Armstrong | 2 | 2011-03-01 00:00:00 | +---------+----------------+-------------+---------------------+
user_id表的主键,name表示用户名,login_times表示该用户的登录次数,每次用户登录后,login_times会自增,而last_login_time更新为当前时间。
REDIS的设计
关系型数据转化为KV数据库,我的方法如下:
key 表名:主键值:列名
value 列值
一般使用冒号做分割符,这是不成文的规矩。比如在php-admin for redis系统里,就是默认以冒号分割,于是user:1 user:2等key会分成一组。于是以上的关系数据转化成kv数据后记录如下:
Set login:1:login_times 5 Set login:2:login_times 1 Set login:3:login_times 2 Set login:1:last_login_time 2011-1-1 Set login:2:last_login_time 2011-2-1 Set login:3:last_login_time 2011-3-1 set login:1:name ”ken thompson“ set login:2:name “dennis ritchie” set login:3:name ”Joe Armstrong“
这样在已知主键的情况下,通过get、set就可以获得或者修改用户的登录次数和最后登录时间和姓名。
一般用户是无法知道自己的id的,只知道自己的用户名,所以还必须有一个从name到id的映射关系,这里的设计与上面的有所不同。
set "login:ken thompson:id" 1 set "login:dennis ritchie:id" 2 set "login: Joe Armstrong:id" 3
这样每次用户登录的时候业务逻辑如下(python版),r是redis对象,name是已经获知的用户名。
1 |
#获得用户的id |
2 |
uid = r.get( "login:%s:id" % name)
|
3 |
#自增用户的登录次数 |
4 |
ret = r.incr( "login:%s:login_times" % uid)
|
5 |
#更新该用户的最后登录时间 |
6 |
ret = r. set ( "login:%s:last_login_time" % uid, datetime.datetime.now())
|
如果需求仅仅是已知id,更新或者获取某个用户的最后登录时间,登录次数,关系型和kv数据库无啥区别。一个通过btree pk,一个通过hash,效果都很好。
假设有如下需求,查找最近登录的N个用户。开发人员看看,还是比较简单的,一个sql搞定。
1 |
select * from login order by last_login_time desc limit N
|
DBA了解需求后,考虑到以后表如果比较大,所以在last_login_time上建个索引。执行计划从索引leafblock 的最右边开始访问N条记录,再回表N次,效果很好。
过了两天,又来一个需求,需要知道登录次数最多的人是谁。同样的关系型如何处理?DEV说简单
1 |
select * from login order by login_times desc limit N
|
DBA一看,又要在login_time上建立一个索引。有没有觉得有点问题呢,表上每个字段上都有素引。
关系型数据库的数据存储的的不灵活是问题的源头,数据仅有一种储存方法,那就是按行排列的堆表。统一的数据结构意味着你必须使用索引来改变sql的访问路径来快速访问某个列的,而访问路径的增加又意味着你必须使用统计信息来辅助,于是一大堆的问题就出现了。
没有索引,没有统计计划,没有执行计划,这就是kv数据库。
redis里如何满足以上的需求呢? 对于求最新的N条数据的需求,链表的后进后出的特点非常适合。我们在上面的登录代码之后添加一段代码,维护一个登录的链表,控制他的长度,使得里面永远保存的是最近的N个登录用户。
1 |
#把当前登录人添加到链表里 |
2 |
ret = r.lpush( "login:last_login_times" , uid)
|
3 |
#保持链表只有N位 |
4 |
ret = redis.ltrim( "login:last_login_times" , 0 , N - 1 )
|
这样需要获得最新登录人的id,如下的代码即可
1 |
last_login_list = r.lrange( "login:last_login_times" , 0 , N - 1 )
|
另外,求登录次数最多的人,对于排序,积分榜这类需求,sorted set非常的适合,我们把用户和登录次数统一存储在一个sorted set里。
zadd login:login_times 5 1 zadd login:login_times 1 2 zadd login:login_times 2 3
这样假如某个用户登录,额外维护一个sorted set,代码如此
1 |
#对该用户的登录次数自增1 |
2 |
ret = r.zincrby( "login:login_times" , 1 , uid)
|
那么如何获得登录次数最多的用户呢,逆序排列取的排名第N的用户即可
1 |
ret = r.zrevrange( "login:login_times" , 0 , N - 1 )
|
可以看出,DEV需要添加2行代码,而DBA不需要考虑索引什么的。
TAG系统
tag在互联网应用里尤其多见,如果以传统的关系型数据库来设计有点不伦不类。我们以查找书的例子来看看redis在这方面的优势。
关系型数据库的设计
两张表,一张book的明细,一张tag表,表示每本的tag,一本书存在多个tag。
mysql> select * from book; +------+-------------------------------+----------------+ | id | name | author | +------+-------------------------------+----------------+ | 1 | The Ruby Programming Language | Mark Pilgrim | | 1 | Ruby on rail | David Flanagan | | 1 | Programming Erlang | Joe Armstrong | +------+-------------------------------+----------------+ mysql> select * from tag; +---------+---------+ | tagname | book_id | +---------+---------+ | ruby | 1 | | ruby | 2 | | web | 2 | | erlang | 3 | +---------+---------+ 假如有如此需求,查找即是ruby又是web方面的书籍,如果以关系型数据库会怎么处理?
1 |
select b. name , b.author from tag t1, tag t2, book b
|
2 |
where t1.tagname = 'web' and t2.tagname = 'ruby' and t1.book_id = t2.book_id and b.id = t1.book_id
|
tag表自关联2次再与book关联,这个sql还是比较复杂的,如果要求即ruby,但不是web方面的书籍呢?
关系型数据其实并不太适合这些集合操作。
REDIS的设计
首先book的数据肯定要存储的,和上面一样。
set book:1:name ”The Ruby Programming Language” Set book:2:name ”Ruby on rail” Set book:3:name ”Programming Erlang” set book:1:author ”Mark Pilgrim” Set book:2:author ”David Flanagan” Set book:3:author ”Joe Armstrong”
tag表我们使用集合来存储数据,因为集合擅长求交集、并集
sadd tag:ruby 1 sadd tag:ruby 2 sadd tag:web 2 sadd tag:erlang 3
那么,即属于ruby又属于web的书?
inter_list = redis.sinter("tag.web", "tag:ruby")
即属于ruby,但不属于web的书?
inter_list = redis.sdiff("tag.ruby", "tag:web")
属于ruby和属于web的书的合集?
inter_list = redis.sunion("tag.ruby", "tag:web")
简单到不行阿。
从以上2个例子可以看出在某些场景里,关系型数据库是不太适合的,你可能能够设计出满足需求的系统,但总是感觉的怪怪的,有种生搬硬套的感觉。
尤其登录系统这个例子,频繁的为业务建立索引。放在一个复杂的系统里,ddl(创建索引)有可能改变执行计划。导致其它的sql采用不同的执行计 划,业务复杂的老系统,这个问题是很难预估的,sql千奇百怪。要求DBA对这个系统里所有的sql都了解,这点太难了。这个问题在oracle里尤其严 重,每个DBA估计都碰到过。对于MySQL这类系统,ddl又不方便(虽然现在有online ddl的方法)。碰到大表,DBA凌晨爬起来在业务低峰期操作,这事我没少干过。而这种需求放到redis里就很好处理,DBA仅仅对容量进行预估即可。
未来的OLTP系统应该是kv和关系型的紧密结合。
相关推荐
2、Redis 相比 memcached 有哪些优势? 3、Redis 支持哪几种数据类型? 4、Redis 主要消耗什么物理资源? 5、Redis 的全称是什么? 6、Redis 有哪几种数据淘汰策略? 7、Redis 官方为什么不提供 Windows 版本? 8、...
2、Redis 相比 memcached 有哪些优势? 3、Redis 支持哪几种数据类型? 4、Redis 主要消耗什么物理资源? 5、Redis 的全称是什么? 6、Redis 有哪几种数据淘汰策略? 7、Redis 官方为什么不提供 Windows 版本? 8、...
redis是基于内存的key-value数据库,比传统的关系型数据库在性能方面有非常大的优势。,利用Redis可以解决高并发的数据访问问题,同时Redis又可以与许多的集群架构进行整合处理。通过学习python操作redis数据库,...
redis又被称作是NOsql,先不管它叫啥,总之就是可以解决关系型数据库在应用场景所面临的一些性能问题,因为它是基于内存存储的,查找速度很快,号称是关系型数据库查找速度的50倍,当然了,redis也有持久化存储,当你...
最近,像Twitter和Facebook这样需要对大量数据进行更新和查询的网络服务不断增加,面向列的数据库的优势对其中一些服务是非常有用的,但是由于这与本书所要介绍的内容关系不大,就不进行详细介绍了。 总结: ...
3.优势 4 4.应用场景 4 2、 redis的安装 4 一:redes准备 4 1.官网 4 2.gcc环境 5 3.效果 6 4.上传 6 5.新建一个目录存放解压的redis 6 6.解压 7 二:安装 7 1.进入redis目录进行基本的编译 7 2.基本的安装 8 3.拷贝...
文章目录一.redis简介1.1 什么是redis1.2 NoSQL1.2.1 NoSQL与关系型数据库的比较1.2.2 非关系型数据库的优势:1.2.3 关系型数据库的优势1.2.4 图片描述1.3 主流NoSQL产品工具二. 下载与安装三. 常用命令操作3.1 数据...
但是到了⼤数据时代,⼈们更多的数据和物联⽹加⼊的数据已经超出了关系数据库的承载范围。 ⼤数据时代初期,随着数据请求并发量⼤不断增⼤,⼀般都是采⽤的集群同步数据的⽅式处理,就是将数据库分成了很多的⼩库,...
基于SpringBoot+Shiro+JWT+Redis+MongoDb+Mysql 进行实现的 主要包括 装修页面、商品管理、订单管理、活动管理、优惠券管理、权限管理等 MySQL 是一款广受欢迎的开源关系型数据库管理系统(RDBMS),由瑞典MySQL AB...
Mysql在大数据量时效率显著下降,MongoDB更多时候作为关系数据库的一种替代。 mongodb更吃内存,因为当mongo发现内存不够的时候,是以2的指数级别来申请内存的。所以一般都建议把mongodb单独放。 其实可以说redis更...
Redis入门到项目实战视频培训教程,除了redis安装、缓存、集群、命令等内容,本套课程...redis是基于内存的key-value数据库,比传统的关系型数据库在性能方面有非常大的优势。作为架构师,redis是必须要掌握的技能!
MySQL 是一款广受欢迎的开源关系型数据库管理系统(RDBMS),由瑞典MySQL AB公司开发,现隶属于美国甲骨文公司(Oracle)。自1998年首次发布以来,MySQL以其卓越的性能、可靠性和可扩展性,成为全球范围内Web应用...
MySQL 是一款广受欢迎的开源关系型数据库管理系统(RDBMS),由瑞典MySQL AB公司开发,现隶属于美国甲骨文公司(Oracle)。自1998年首次发布以来,MySQL以其卓越的性能、可靠性和可扩展性,成为全球范围内Web应用...
MySQL 是一款广受欢迎的开源关系型数据库管理系统(RDBMS),由瑞典MySQL AB公司开发,现隶属于美国甲骨文公司(Oracle)。自1998年首次发布以来,MySQL以其卓越的性能、可靠性和可扩展性,成为全球范围内Web应用...
MySQL 是一款广受欢迎的开源关系型数据库管理系统(RDBMS),由瑞典MySQL AB公司开发,现隶属于美国甲骨文公司(Oracle)。自1998年首次发布以来,MySQL以其卓越的性能、可靠性和可扩展性,成为全球范围内Web应用...
MySQL 是一款广受欢迎的开源关系型数据库管理系统(RDBMS),由瑞典MySQL AB公司开发,现隶属于美国甲骨文公司(Oracle)。自1998年首次发布以来,MySQL以其卓越的性能、可靠性和可扩展性,成为全球范围内Web应用...
Redis 是一个使用 C 语言写成的,开源、基于内存、可选持久性的、非关系型,key-value数据库 2.Redis有什么优点? 速度快:因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1) ...
MySQL 是一款广受欢迎的开源关系型数据库管理系统(RDBMS),由瑞典MySQL AB公司开发,现隶属于美国甲骨文公司(Oracle)。自1998年首次发布以来,MySQL以其卓越的性能、可靠性和可扩展性,成为全球范围内Web应用...
本文实例讲述了Python实现的登录验证系统。...两者结合使用发挥各自的优势已是当下流行的数据库使用方式。 开发语言:Python。 MVC框架:MVC全名是Model View Controller,是模型(model)-视图(view)-控制器
MySQL 是一款广受欢迎的开源关系型数据库管理系统(RDBMS),由瑞典MySQL AB公司开发,现隶属于美国甲骨文公司(Oracle)。自1998年首次发布以来,MySQL以其卓越的性能、可靠性和可扩展性,成为全球范围内Web应用...