【redis专题(11)】KEY设计原则与技巧

对比着关系型数据库,咱们对redis key的设计通常有如下两种格式:javascript

  • 表名:主键名:主键值:列名
  • 表名:主键值:列名 在全部主键名都是id的状况下(其实我我的不喜欢这种状况,好比user表,它的主键名就应该是user_id,而不是id,这样在表与表之间关联的时候一目了然)
用冒号做为分割是设计key的一种不成文的原则,遵循这种格式设计出的key在某些redis客户端下能够有效的识别;

key设计技巧.jpg-120.9kB

可是,在关系型数据中,除主键外,还有可能根据其余列来查询。
如上表中, username 也是极频繁查询的,每每这种列也是加了索引的。
转换到k-v数据中,则也要相应的生成一条按照该列为主的key-value。php

Set user:username:lisi:uid  9  #可是要保证username是惟一的; 这样,咱们能够根据username:lisi:uid ,查出userid=9, 再查user:9:password/email ...

mysql与redis的数据转换实例

mysql数据准备html

CREATE TABLE `book` (
  `book_id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(100) NOT NULL DEFAULT '' COMMENT '书名',
  `add_time` int(10) NOT NULL DEFAULT '0' COMMENT '添加时间',
  PRIMARY KEY (`book_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='书本表';

INSERT INTO book VALUES (5, 'PHP圣经', UNIX_TIMESTAMP() ), (6, 'ruby实战', UNIX_TIMESTAMP() ), (7, 'mysql运维', UNIX_TIMESTAMP() ), (8, 'ruby服务端编程', UNIX_TIMESTAMP() ); 

CREATE TABLE `tag` (
  `tag_id` int(11) NOT NULL AUTO_INCREMENT,
  `tag_name` char(40) NOT NULL DEFAULT '' COMMENT '标签名',
  PRIMARY KEY (`tag_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='标签表';

INSERT INTO tag VALUES (1, 'PHP'), (2, 'ruby'), (3, 'mysql'), (4, 'database');

CREATE TABLE `tag_book` (
  `tag_id` int(11) NOT NULL DEFAULT '0' COMMENT '标签ID',
  `book_id` int(11) NOT NULL DEFAULT '0' COMMENT '书ID',
  KEY `tag_id` (`tag_id`),
  KEY `book_id` (`book_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='标签与书关系表';

INSERT INTO `tag_book` (`tag_id`, `book_id`) VALUES ('4', '7'),('1', '5'),('2', '6'),('2', '8');

咱们有如下查询需求:java

# 《mysql运维》有几个标签:
SELECT tag_name FROM `book` AS b INNER JOIN tag_book AS tb ON b.book_id = tb.book_id INNER JOIN tag AS t ON tb.tag_id = t.tag_id WHERE `name` = 'mysql运维';
    
# 标签ruby下有几本书:
SELECT b.name FROM `book` AS b INNER JOIN tag_book AS tb ON b.book_id = tb.book_id INNER JOIN tag AS t ON tb.tag_id = t.tag_id WHERE t.`tag_name` = 'ruby';

换到redis中,咱们能够以下操做:mysql

一个标签下面能够包含不少书籍,一个书籍也能够包含不少标签。这种从属关系若是没有排序需求的,咱们可使用集合:web

  1. 能够准确表达从属关系,一个标签PHP的集合下面有:哪些书籍(存ID就能够了)
  2. 集合不只能够方便CURD,还能够求并集交集等
set book:book_id:5:name 'PHP圣经'
set book:book_id:6:name 'ruby实战'
set book:book_id:7:name 'mysql运维'
set book:book_id:8:name 'ruby服务端编程'


sadd tag:tag_name:php:book_id 5
sadd tag:tag_name:ruby:book_id 6 8
sadd tag:tag_name:database:book_id 7
sadd tag:tag_name:mysql:book_id 7


# ruby下面有哪些书
127.0.0.1:6379> sort tag:tag_name:ruby:book_id get book:book_id:*:name
ruby实战
ruby服务端编程 

# 标签同时包含mysql,与database的书 【取交集】
127.0.0.1:6379> sinter tag:tag_name:database:book_id tag:tag_name:mysql:book_id
7 
# 在根据book:book_id:7:name得到书籍名称,但若是返回的数据量大,能够先添加一个store参数存到一个临时集合里,而后再用sort分页取回;

# 查全部的PHP以及mysql的书;【取并集】
127.0.0.1:6379> sunion tag:tag_name:php:book_id tag:tag_name:mysql:book_id
5
7

set book:book_id:9:name 'javascript权威指南'
set book:book_id:10:name 'HTML+CSS'
sadd tag:tag_name:web:book_id 5 9 10

#查web标签中的非PHP书籍
127.0.0.1:6379> sdiff tag:tag_name:web:book_id tag:tag_name:php:book_id
9
10

总结以下:

  1. 表达从属关系(一对多,多对多),最好用集合; 好比: 书名和标签,关注与被关注(微博粉丝关系)等等。
  2. 求最近的,通常利用链表后入后出的特性。好比:最近N个登陆的用户,能够维护一个登陆的链表,控制他的长度,使得里面永远保存的是最近的N个登陆用户。
  3. 对于排序,积分榜这类需求,能够用有序集合,好比:咱们把用户和登陆次数统一存储在一个sorted set里,而后就能够求出登陆次数最多用户。
  4. 对于大数据量的非是即否关系,还能够经过位图(setbit)的方式,好比:1亿个用户, 每一个用户 登录/作任意操做,记为今天活跃,不然记为不活跃;(天天一个位图来记录,会员id就是位图的位置);

mysql导出数据到redis

http://ju.outofmemory.cn/entr...
http://www.cnblogs.com/kgdxpr...redis

相关文章
相关标签/搜索