Redis数据模型

作者: 壹点零 | 来源:发表于2018-02-08 15:06 被阅读0次
    数据类型

    Redis key 值是二进制安全的,这意味着可以用任何二进制序列作为key值,从形如”foo”的简单字符串到一个JPEG文件的内容都可以。空字符串也是有效key值。

    Key取值原则:
    1、键值不需要太长,消耗内存,且在数据中查找这类键值的计算成本较高
    2、键值不宜过短,可读性较差

    字符串

    字符串是一种最基本的Redis值类型。Redis字符串是二进制安全的,这意味着一个Redis字符串能包含任意类型的数据。
    例如: 一张JPEG格式的图片或者一个序列化的java对象

    一个字符串类型的值最多能存储512M字节的内容

    String命令

    1. 设置字符串值 set get
      SET key value [EX seconds] [PX milliseconds] [NX|XX]
      EX 设置过期时间,秒,等同于SETEX key seconds value
      PX 设置过期时间,毫秒,等同于PSETEX key milliseconds value
      NX 键不存在,才能设置,等同于SETNX key value
      XX 键存在时,才能设置

    2. 设置多个键的字符串值
      MSET key value [key value ...]

    3. 键不存在时,设置字符串值
      MSETNX key value [key value ...]
      注意:这是原子操作

    set s1 abc
    set s2 12
    set se abc ex 15
    
    mset s3 3 s4 4 s5 5
    msetnx s5 A5 s6 6
    
    1. 过期
      Redis中可以给Key设置一个生存时间(秒或毫秒),当达到这个时长后,这些键值将会被自动删除

    2. 设置多少秒或者毫秒后过期
      EXPIRE key seconds
      get key
      set key val ex 10
      PEXPIRE key milliseconds

    3. 设置在指定Unix时间戳过期
      EXPIREAT key timestamp
      PEXPIREAT key milliseconds-timestamp

    4. 删除过期
      PERSIST key

    5. 生存时间
      Time To Live,Key的剩余生存时间

    6. 查看剩余生存时间
      TTL key
      PTTL key
      key存在但没有设置TTL,返回-1
      key存在,但还在生存期内,返回剩余的秒或者毫秒
      key曾经存在,但已经消亡,返回-2(2.8版本之前返回-1)

    set se abc ex 15
    ttl s6
    expire s6 60
    pttl s6
    persist s6
    pttl s6
    
    EXPIREAT cache 1355292000
    PEXPIREAT mykey 1555555555005
    
    1. 获取值
      GET key

    2. 获取多个给定的键的值
      MGET key [key ...]

    3. 返回旧值并设置新值
      GETSET key value
      如果键不存在,就创建并赋值

    4. 字符串长度
      STRLEN key

    5. 查找键
      KEYS pattern

    6. pattern取值
      * 任意长度字符
      ? 任意一个字符
      [] 字符集合,表示可以是集合中的任意一个

    keys s*
    keys s?
    keys s[13]
    keys *
    keys ??
    
    1. 键类型
      TYPE key
      object encoding key
      key:
      1. v:(K1)
      2. type:string
      3. enco..(raw/int)
      4. strlen:2
      5. 指针 value地址

    encoding,strlen:增删改:更新 查询长度,还是数值计算,成本很高

    1. 键是否存在
      EXISTS key

    2. 键重命名
      RENAME key newkey
      RENAMENX key newkey

    3. 键删除
      DEL key [key ...]

    4. 追加字符串
      APPEND key value
      如果键存在就追加;如果不存在就等同于SET key value

    5. 获取子字符串 索引
      GETRANGE key start end
      索引值从0开始,负数表示从字符串右边向左数起,-1表示最有一个字符

    索引
    1. 覆盖字符串
      SETRANGE key offset value
    APPEND s6 123
    getrange s1 1 2
    getrange s1 0 -1
    getrange s1 -2 -1
    getrange s1 0 10000
    SETRANGE s6 3 e
    SETRANGE s6 3 efghijk
    SETRANGE newkey 5 hello
    SETRANGE s6 3 efghijk
    
    1. 步长1的增减
      INCR key
      DECR key
      字符串值会被解释成64位有符号的十进制整数来操作,结果依然转成字符串

    2. 步长增减 float
      INCRBY key decrement
      DECRBY key decrement
      字符串值会被解释成64位有符号的十进制整数来操作,结果依然转成字符串

    位图bitmap 【字节数组】

    存储结构

    位图不是真正的数据类型,它是定义在字符串类型中
    一个字符串类型的值最多能存储512M字节的内容
    位上限:2^(9+10+10+3) = 2^32b

    获取数据出现乱码时,转换乱码命令:
    redis-cli --raw 退出客户端,重新登录。

    1. 设置某一上的值
      SETBIT key offset value (0/1)
      offset偏移量,从0开始

    2. 获取某一位上的值
      GETBIT key offset

    3. 返回指定值0或者1在指定区间上第一次出现的位置偏移量
      BITPOS key bit [start] [end]
      bitpos k1 1 1 1
      k2: 0 1 0 0 0 0 1 0 0 1 0 0 0 0 0 0
      k3: 0 1 0 0 0 0 1 0
      0 1 0 1 0 0 0 1 0 1 0 0 0 0 1 0
      setbit k1 1 1

    set str1 ab
    setbit str1 6 1
    setbit str1 7 0
    get str1
    这个结果是什么?
    
    1. 统计指定位区间上值为1的个数 字节
      BITCOUNT key [start] [end] > start end Byte的索引 正负方向
    set k ab
    bitcount k 1 1
    

    从左向右从0开始,从右向左从-1开始,注意官方start、end是位,测试后是字节
    BITCOUNT testkey 0 0表示从索引为0个字节到索引为0个字节,就是第一个字节的统计
    BITCOUNT testkey 0 -1等同于BITCOUNT testkey
    最常用的就是 BITCOUNT testkey

    1. 位操作
      0 1 0 0 0 0 0 1
      1 1 1 0 0 0 0 1
      0 1 0 0 0 0 0 1

    对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上,operation 可以是 AND 、 OR 、 NOT 、 XOR 这四种操作中的任意一种:

    BITOP AND destkey key [key ...] ,对一个或多个 key 求逻辑并,并将结果保存到 destkey;
    BITOP OR destkey key [key ...] ,对一个或多个 key 求逻辑或,并将结果保存到 destkey;
    BITOP XOR destkey key [key ...] ,对一个或多个 key 求逻辑异或,并将结果保存到 destkey;
    BITOP NOT destkey key ,对给定 key 求逻辑非,并将结果保存到 destkey。

    除了 NOT 操作之外,其他操作都可以接受一个或多个 key 作为输入
    当 BITOP 处理不同长度的字符串时,较短的那个字符串所缺少的部分会被看作 0
    空的 key 也被看作是包含 0 的字符串序列
    思考:a位或b是什么?

    1. Redis的二进制位
    set s1 ab
    bitcount s1
    bitcount s1 0 0
    bitcount s1 1 1
    set ch 中
    bitcount ch
    bitcount ch 2 2
    
    1 2 3
    1. 网站用户的上线次数统计(活跃用户)
      用户ID为key,天作为offset,上线置为1 366> 000000000000000
      366 /8 50Byte 16 50
      key: sean value: 11 1 000000000000000001010000000000000000
      ID为500的用户,今年的第1天上线、第30天上线
      SETBIT u500 1 1 1 0 0 000 0 …….1 0 00 0 > 365 /8 46 Byte
      SETBIT u500 30 1
      BITCOUNT sean 0 -1
      KYES u*

    2. 按天统计网站活跃用户
      天作为key,用户ID为offset,上线置为1
      求一段时间内活跃用户数 500 / 8 366 * 63Byte
      SETBIT 20160601 15 1 1 1 0 1 00 00 00 0 00 00 0
      SETBIT 20160603 123 1 0 1 0 0 00 00 01 0 00 00 0
      SETBIT 20160606 123 1 0 1 0 0 00 00 01 0 00 00 0
      求6月1日到6月10日的活跃用户
      BITOP OR aaa 20160601 20160602 20160603 20160610
      BITCOUNT aaa 0 -1
      结果为2

    登录不同的库
    redis-cli --help
    redis-cli -n 2

    清除当前库数据
    FLUSHDB

    清除所有库中的数据
    FLUSHALL

    列表 (List列表 数组)

    基于Linked List实现;
    元素是字符串类型;
    列表头尾增删快,中间增删慢,增删元素是常态;
    元素可以重复出现;
    最多包含2^32-1元素.

    列表结构图

    列表的索引
    从左至右,从0开始
    从右至左,从-1开始

    列表索引
    1. list
      队列:L/R R/L
      栈: L/L R/R
      数组:LINDEX LSET
      阻塞:BL BR

    2. 命令说明
      B block 块,阻塞
      L left 左
      R right 右
      X exist 存在

    3. 左右或者头尾压入元素 string set key “abc”
      LPUSH key value [value ...]
      LPUSHX key value
      RPUSH key value [value ...]
      RPUSHX key value

    4. 左右或者头尾弹出元素
      LPOP key
      RPOP key

    5. 从一个列表尾部弹出元素压入到另一个列表的头部 string getset
      RPOPLPUSH source destination

    6. 返回列表中指定范围元素
      LRANGE key start stop
      LRANGE key 0 -1 表示返回所有元素

    7. 获取指定位置的元素
      LINDEX key index

    8. 设置指定位置元素的值
      LSET key index value

    9. 列表长度,元素个数 string strlen
      LLEN key LRANGE KEY 0 -1

    10. 从列表头部开始删除值等于value的元素count次,LIST 可以重复出现
      LREM key count value
      count > 0 : 从表头开始向表尾搜索,移除与 value 相等的元素,数量为 count
      count < 0 : 从表尾开始向表头搜索,移除与 value 相等的元素,数量为 count 的绝对值
      count = 0 : 移除表中所有与 value 相等的值

    举例
    RPUSH listkey c abc c ab 123 ab bj ab redis list
    LREM listkey 2 ab
    LRANGE listkey 0 -1

    image.png
    1. 去除指定范围 元素
      LTRIM key start stop

    举例
    RPUSH listkey c abc c ab 123 ab bj ab redis list
    LTRIM listkey 0 -1
    LTRIM listkey 1 -1
    LTRIM listkey 1 10000

    微博的评论最后500条
    LTRIM u1234:forumid:comments 0 499

    1. 在列表中某个存在的值(pivot)前或后插入元素
      LINSERT key BEFORE|AFTER pivot value
      key和pivot不存在,不进行任何操作

    举例
    RPUSH lst Clojure C Lua
    LINSERT lst AFTER C Python
    LINSERT lst BEFORE C Ruby

    image.png
    1. 阻塞
      如果弹出的列表不存在或者为空,就会阻塞
      超时时间设置为0,就是永久阻塞,直到有数据可以弹出
      如果多个客户端阻塞在同一个列表上,使用First In First Service原则,先到先服务

    2. 左右或者头尾阻塞弹出元素
      BLPOP key [key ...] timeout
      BRPOP key [key ...] timeout

    3. 从一个列表尾部阻塞弹出元素压入到另一个列表的头部
      BRPOPLPUSH source destination timeout

    Hash散列

    由field和关联的value组成的map键值对;
    field和value是字符串类型;
    一个hash中最多包含2^32-1键值对。

    数据结构

    Hash命令

    1. 设置单个字段
      HSET key field value
      HSETNX key field value (key的filed不存在的情况下执行,key不存在直接创建)

    2. 设置多个字段
      HMSET key field value [field value ...]

    3. 返回字段个数
      HLEN key

    4. 判断字段是否存在
      HEXISTS key field
      key或者field不存在,返回0

    5. 返回字段值
      HGET key field

    6. 返回多个字段值
      HMGET key field [field ...]

    7. 返回所有的键值对
      HGETALL key

    8. 返回所有字段名
      HKEYS key

    9. 返回所有值
      HVALS key

    10. 在字段对应的值上进行整数的增量计算
      HINCRBY key field increment

    11. 在字段对应的值上进行浮点数的增量计算
      HINCRBYFLOAT key field increment

    12. 删除指定的字段
      HDEL key field [field ...]

    举例
    HINCRBY numbers x 100
    HINCRBY numbers x -50
    HINCRBYFLOAT numbers x 3.14
    HDEL numbers x

    Hash用途

    1.节约内存空间;
    2.每创建一个键,它都会为这个键储存一些附加的管理信息(比如这个键的类型,这个键最后一次被访问的时间等等);
    3.所以数据库里面的键越多,redis数据库服务器在储存附加管理信息方面耗费的内存就越多,花在管理数据库键上的CPU也会越多在字段对应的值上进行浮点数的增量计算。

    image.png
    1. 不适合hash的情况

      1. 使用二进制位操作命令:因为Redis目前支持对字符串键进行SETBIT、GETBIT、BITOP等操作,如果你想使用这些操作,那么只能使用字符串键,虽然散列也能保存二进制数据
      2. 使用过期键功能:Redis的键过期功能目前只能对键进行过期操作,而不能对散列的字段进行过期操作,因此如果你要对键值对数据使用过期功能的话,那么只能把键值对储存在字符串里面
    2. 微博的好友关注
      用户ID为key,Field为好友ID,Value为关注时间
      user:1000 user:606 20150808
      xz pl 2011 zs 1949

    3. 用户维度统计
      统计数包括:关注数、粉丝数、喜欢商品数、发帖数
      用户为Key,不同维度为Field,Value为统计数
      比如关注了5人
      HSET user:100000 follow 5
      HINCRBY user:100000 follow 1

    Set集合

    无序的、去重的;
    元素是字符串类型;
    最多包含2^32-1元素。

    数据结构图

    Set命令

    1. 增加一个或多个元素
      SADD key member [member ...]
      如果元素已经存在,则自动忽略

    举例
    SADD friends peter
    SADD friends jack tom john
    SADD friends may tom

    1
    1. 移除一个或者多个元素
      SREM key member [member ...]
      元素不存在,自动忽略

    举例
    SREM friends peter
    SREM friends tom john

    2
    1. 返回集合包含的所有元素
      SMEMBERS key
      如果集合元素过多,例如百万个,需要遍历,可能会造成服务器阻塞,生产环境应避免使用

    2. 检查给定元素是否存在于集合中
      SISMEMBER key member

    3. 集合的无序性
      SADD friendsnew "peter" "jack" "tom" "john" "may" "ben"
      SADD anotherfriends "peter" "jack" "tom" "john" "may" "ben"
      SMEMBERS friends
      SMEMBERS anotherfriends
      注意, SMEMBERS 有可能返回不同的结果,所以,如果需要存储有序且不重复的数据使用有序集合,存储有序可重复的使用列表

    4. 随机返回集合中指定个数的
      SRANDMEMBER key [count]
      如果 count 为正数,且小于集合基数,那么命令返回一个包含 count 个元素的数组,数组中的元素各不相同。如果 count 大于等于集合基数,那么返回整个集合 最多返回整个集合 conut>=0
      如果 count 为负数,那么命令返回一个数组,数组中的元素可能会重复出现多次,而数组的长度为 count 的绝对值 count < 0 长度为count绝对值,元素可能重复
      如果 count 为 0,返回空
      如果 count 不指定,随机返回一个元素

    举例
    SADD friend "peter" "jack" "tom" "john" "may" "ben"
    SRANDMEMBER friends 3
    SRANDMEMBER friends -5

    1. 返回集合中元素的个数
      SCARD key
      键的结果会保存信息,集合长度就记录在里面,所以不需要遍历

    2. 随机从集合中移除并返回这个被移除的元素
      SPOP key

    3. 把元素从源集合移动到目标集合
      SMOVE source destination member

    4. 差集
      SDIFF key [key ...],从第一个key的集合中去除其他集合和自己的交集部分
      SDIFFSTORE destination key [key ...],将差集结果存储在目标key中

    举例
    SADD number1 123 456 789
    SADD number2 123 456 999
    SDIFF number1 number2

    10
    1. 交集
      SINTER key [key ...],取所有集合交集部分
      SINTERSTORE destination key [key ...],将交集结果存储在目标key中

    举例
    SADD number1 123 456 789
    SADD number2 123 456 999
    SINTER number1 number2

    11
    1. 并集
      SUNION key [key ...],取所有集合并集
      SUNIONSTORE destination key [key ...],将并集结果存储在目标key中

    举例
    SADD number1 123 456 789
    SADD number2 123 456 999
    SUNION number1 number2

    12

    新浪微博的共同关注
    需求:当用户访问另一个用户的时候,会显示出两个用户共同关注哪些相同的用户
    设计:将每个用户关注的用户放在集合中,求交集即可
    实现如下:
    peter={'john','jack','may'}
    ben={'john','jack','tom'}
    那么peter和ben的共同关注为:
    SINTER peter ben 结果为 {'john','jack'}

    SortedSet有序集合

    类似Set集合;
    有序的、去重的;
    元素是字符串类型;
    每一个元素都关联着一个浮点数分值(Score),并按照分值从小到大的顺序排列集合中的元素。分值可以相同;
    最多包含2^32-1元素。

    一个保存了水果价格的有序集合 一个保存了员工薪水的有序集合 一个有序集合,保存了正在阅读某些技术书的人数

    SortedSet命令

    1. 增加一个或多个元素
      ZADD key score member [score member ...]
      如果元素已经存在,则使用新的score

    举例
    ZADD fruits 3.2 香蕉
    ZADD fruits 2.0 西瓜
    ZADD fruits 4.0 番石榴 7.0 梨 6.8 芒果

    image.png
    1. 移除一个或者多个元素
      ZREM key member [member ...]
      元素不存在,自动忽略

    举例
    ZREM fruits 番石榴 梨 芒果
    ZREM fruits 西瓜

    image.png
    1. 显示分值
      ZSCORE key member

    举例
    ZSCORE fruits 芒果
    ZSCORE fruits 西瓜

    image.png

    计算机并不能精确表达每一个浮点数,都是一种近似表达

    1. 增加或者减少分值
      ZINCRBY key increment member
      increment为负数就是减少

    举例
    ZINCRBY fruits 1.5 西瓜
    ZINCRBY fruits -0.8 香蕉

    image.png
    1. 返回元素的排名(索引)
      ZRANK key member

    元素 分值 索引

    举例
    ZRANK fruits 西瓜
    ZRANK fruits 番石榴
    ZRANK fruits 芒果

    image.png
    1. 返回元素的逆序排名
      ZREVRANK key member

    举例
    ZREVRANK fruits 西瓜
    ZREVRANK fruits 番石榴
    ZREVRANK fruits 芒果

    image.png
    1. 返回指定索引区间元素
      ZRANGE key start stop [WITHSCORES]
      如果score相同,则按照字典序lexicographical order 排列
      默认按照score从小到大,如果需要score从大到小排列,使用ZREVRANGE

    正负方向 0 -1

    举例
    ZRANGE fruits 0 2
    ZRANGE fruits -5 -4

    image.png
    1. 返回指定索引区间元素
      ZREVRANGE key start stop [WITHSCORES]
      如果score相同,则按照字典序lexicographical order 的 逆序 排列
      默认按照score从大到小,如果需要score从小到大排列,使用ZRANGE

    举例
    ZREVRANGE fruits 0 2
    ZREVRANGE fruits -5 -4

    image.png
    1. 返回指定分值区间元素
      ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
      返回score默认属于[min,max]之间,元素按照score升序排列,score相同字典序
      LIMIT中offset代表跳过多少个元素,count是返回几个。类似于Mysql
      使用小括号,修改区间为开区间,例如(5、(10、5)
      -inf和+inf表示负无穷和正无穷

    举例
    ZRANGEBYSCORE fruits 4.0 7.0
    ZRANGEBYSCORE fruits (4 7
    ZRANGEBYSCORE fruits -inf +inf

    image.png
    1. 返回指定分值区间元素
      ZREVRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
      返回score默认属于[min,max]之间,元素按照score降序排列,score相同字典降序
      LIMIT中offset代表跳过多少个元素,count是返回几个。类似于Mysql
      使用小括号,修改区间为开区间,例如(5、(10、5)
      -inf和+inf表示负无穷和正无穷

    举例
    ZREVRANGEBYSCORE fruits 7.0 4.0
    ZRANGEBYSCORE fruits 7 (4
    ZRANGEBYSCORE fruits +inf -inf

    image.png
    1. 移除指定排名范围的元素
      ZREMRANGEBYRANK key start stop

    举例
    ZREMRANGEBYRANK fruits 0 2
    ZRANGE fruits 0 -1

    image.png
    1. 移除指定分值范围的元素
      ZREMRANGEBYSCORE key min max

    举例
    ZREMRANGEBYSCORE fruits 3.0 5.0
    ZRANGE fruits 0 -1

    image.png
    1. 返回集合中元素个数
      ZCARD key

    返回指定范围中元素的个数
    ZCOUNT key min max
    ZCOUNT fruits 4 7
    ZCOUNT fruits (4 7

    image.png
    1. 并集
      ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]
      numkeys指定key的数量,必须
      WEIGHTS选项,与前面设定的key对应,对应key中每一个score都要乘以这个权重
      AGGREGATE选项,指定并集结果的聚合方式
      SUM:将所有集合中某一个元素的score值之和作为结果集中该成员的score值
      MIN:将所有集合中某一个元素的score值中最小值作为结果集中该成员的score值
      MAX:将所有集合中某一个元素的score值中最大值作为结果集中该成员的score值

    举例
    ZADD scores1 70 tom 80 peter 60 john
    ZADD scores2 90 peter 60 ben
    ZUNIONSTORE scores-all 2 scores1 scores2
    ZUNIONSTORE scores-all1 2 scores1 scores2 AGGREGATE SUM
    ZUNIONSTORE scores-all2 2 scores1 scores2 WEIGHTS 1 0.5 AGGREGATE SUM

    1. 交集
      ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]
      numkeys指定key的数量,必须
      WEIGHTS选项,与前面设定的key对应,对应key中每一个score都要乘以这个权重
      AGGREGATE选项,指定并集结果的聚合方式
      SUM:将所有集合中某一个元素的score值之和作为结果集中该成员的score值
      MIN:将所有集合中某一个元素的score值中最小值作为结果集中该成员的score值
      MAX:将所有集合中某一个元素的score值中最大值作为结果集中该成员的score值

    网易音乐排行榜怎么做?

    image.png

    分析
    每首歌的歌名作为元素(先不考虑重复)
    每首歌的播放次数作为分值
    ZREVRANGE来获取播放次数最多的歌曲(就是最多播放榜了,云音乐热歌榜,没有竞价,没有权重)

    新浪微博翻页
    新闻网站、博客、论坛、搜索引擎,页面列表条目多,都需要分页
    blog这个key中使用时间戳作为score
    ZADD blog 1407000000 '今天天气不错'
    ZADD blog 1450000000 '今天我们学习Redis'
    ZADD blog 1560000000 '几个Redis使用示例'
    ZREVRANGE blog 0 10
    ZREVRANGE blog 11 20

    京东图书畅销榜怎么做?
    单日榜,计算出周榜单、月榜单、年榜单

    京东图书畅销榜
    ZADD bookboard-001 1000 'java' 1500 'Redis' 2000 'haoop'
    ZADD bookboard-002 1020 'java' 1500 'Redis' 2100 'haoop'
    ZADD bookboard-003 1620 'java' 1510 'Redis' 3000 'haoop'
    ZUNIONSTORE bookboard-001:003 3 bookboard-001 bookboard-002 bookboard-003,行吗?

    京东图书畅销榜
    ZADD bookboard-001 1000 'java' 1500 'Redis' 2000 'haoop'
    ZADD bookboard-002 1020 'java' 1500 'Redis' 2100 'haoop'
    ZADD bookboard-003 1620 'java' 1510 'Redis' 3000 'haoop'
    ZUNIONSTORE bookboard-001:003 3 bookboard-001 bookboard-002 bookboard-003 AGGREGATE MAX
    并集,使用max
    注意:参与并集运算的集合较多,会造成Redis服务器阻塞,因此最好放在空闲时间或者备用服务器上进行计算。

    相关文章

      网友评论

        本文标题:Redis数据模型

        本文链接:https://www.haomeiwen.com/subject/wzozzxtx.html