资讯专栏INFORMATION COLUMN

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

PascalXie / 1172人阅读

摘要:如上表中,也是极频繁查询的,往往这种列也是加了索引的。转换到数据中,则也要相应的生成一条按照该列为主的。求最近的,一般利用链表后入后出的特性。

对比着关系型数据库,我们对redis key的设计一般有以下两种格式:

表名:主键名:主键值:列名

表名:主键值:列名 在所有主键名都是id的情况下(其实我个人不喜欢这种情况,比如user表,它的主键名就应该是user_id,而不是id,这样在表与表之间关联的时候一目了然)

用冒号作为分割是设计key的一种不成文的原则,遵循这种格式设计出的key在某些redis客户端下可以有效的识别;

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

Set user:username:lisi:uid  9  #但是要保证username是唯一的; 这样,我们可以根据username:lisi:uid ,查出userid=9, 再查user:9:password/email ...
mysql与redis的数据转换实例

mysql数据准备

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");

我们有以下查询需求:

# 《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中,我们可以如下操作:

一个标签下面可以包含很多书籍,一个书籍也可以包含很多标签。这种从属关系如果没有排序需求的,我们可以使用集合:

可以准确表达从属关系,一个标签PHP的集合下面有:哪些书籍(存ID就可以了)

集合不仅可以方便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
总结如下:

表达从属关系(一对多,多对多),最好用集合; 比如: 书名和标签,关注与被关注(微博粉丝关系)等等。

求最近的,一般利用链表后入后出的特性。比如:最近N个登录的用户,可以维护一个登录的链表,控制他的长度,使得里面永远保存的是最近的N个登录用户。

对于排序,积分榜这类需求,可以用有序集合,比如:我们把用户和登录次数统一存储在一个sorted set里,然后就可以求出登录次数最多用户。

对于大数据量的非是即否关系,还可以通过位图(setbit)的方式,比如:1亿个用户, 每个用户 登陆/做任意操作,记为今天活跃,否则记为不活跃;(每天一个位图来记录,会员id就是位图的位置);

mysql导出数据到redis

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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/37285.html

相关文章

  • SQL-SQL优化-索引

    摘要:在库存系统中,最重要的就是要防止超卖。系列创建高性能的索引索引是存储引擎用于快速找到记录的一种数据结构。对查询性能优化最有效的手段。性能优化梳理前言本文主要针对的是关系型数据数据库。用户可以通过特殊的关键字提示优化器,影响的决策过程。 图文并茂详解 SQL JOIN Join 是关系型数据库系统的重要操作之一,一般关系型数据库中包含的常用 Join:内联接、外联接和交叉联接等。如果我们...

    zacklee 评论0 收藏0
  • SQL-SQL优化-索引

    摘要:在库存系统中,最重要的就是要防止超卖。系列创建高性能的索引索引是存储引擎用于快速找到记录的一种数据结构。对查询性能优化最有效的手段。性能优化梳理前言本文主要针对的是关系型数据数据库。用户可以通过特殊的关键字提示优化器,影响的决策过程。 图文并茂详解 SQL JOIN Join 是关系型数据库系统的重要操作之一,一般关系型数据库中包含的常用 Join:内联接、外联接和交叉联接等。如果我们...

    kk_miles 评论0 收藏0
  • redis专题(8)】命令语法介绍之通用KEY

    摘要:通配任意多个字符包括没有如和等。通配括号内的某个字符如和,但不匹配。查询的生命周期默认永久有效单位秒数如果为单位就变为毫秒不让失效从当前数据库中随机返回不删除一个。 基础命令 select num 数据库选择 默认有16[0到15]个数据库,默认自动选择0号数据库 move key num 移动key到num服务器 del key [key ...] 删除给定的一个或多个 ke...

    elina 评论0 收藏0
  • 【mysql的设计优化专题(4)】表的垂直拆分和水平拆分

    摘要:比如我们是按年来进行归档拆分的这个时候在页面设计上就约束用户必须要先选择年然后才能进行查询在做分析或者统计时,由于是自己人的需求多点等待其实是没关系的并且并发很低这个时候可以用把所有表都组合成一张视图来进行查询然后再进行查询 垂直拆分 垂直拆分是指数据表列的拆分,把一张列比较多的表拆分为多张表showImg(https://segmentfault.com/img/remote/146...

    Leo_chen 评论0 收藏0
  • 手撕面试官系列(四 ):MongoDB+Redis 面试专题

    摘要:面试题答案领取方式见个人主页你说的数据库是什么意思与直接有什么区别为什么要使用和不使用数据库说一说数据库的几个优点数据库有哪些类型与之间最基本的差别是什么你怎么比较及成为最好数据库的原因是什么位系统上有什么细微差别回放在条目不完整时比如恰巧 MongoDBshowImg(https://segmentfault.com/img/remote/1460000019776836);(面试题...

    MingjunYang 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<