Redis五种基本数据类型介绍

五种基本数据类型

参考资料:https://redis.io/docs/latest/commands/

String

简介

  • string,字符串类型,本质是字节数组。包括三种形式:普通字符串;整数字符串;浮点数字符串。

  • 特点:

    • 二进制安全。任意二进制序列都被视作纯粹的字节数组,可以被正确的存储和读取,不会因为二进制序列中包含特定的值(如零值字节 \0)而进行特殊处理(如截断)。相比之下,c语言字符串以\0作为字符串的结尾,是非二进制安全的。

    • O(1)时间复杂度内获取字符串的字节长度。

    • 支持动态扩容。

    • 预分配空间机制。

    • 兼容c语言字符串。

    • 上限为512mb。

      • 6.0版本以前这个值在源码中写死。

        // v5.0.5 src/t_string.c
        static int checkStringLength(client *c, long long size) {
            if (size > 512*1024*1024) {
                addReplyError(c,"string exceeds maximum allowed size (512MB)");
                return C_ERR;
            }
            return C_OK;
        }
        
      • 6.0版本(v6.0.7)以后,可通过redis.conf中的proto-max-bulk-len 512mb进行配置。一般不建议修改,否则可能出现“大key”问题。

        // v6.0.7 src/t_string.c
        static int checkStringLength(client *c, long long size) {
            if (!(c->flags & CLIENT_MASTER) && size > server.proto_max_bulk_len) {
                addReplyError(c,"string exceeds maximum allowed size (proto-max-bulk-len)");
                return C_ERR;
            }
            return C_OK;
        }
        

常用命令

  • SET:写入key和string类型的value。(新增或修改)

    • 语法:SET key value [EX seconds|PX milliseconds] [NX|XX] [GET]
      • EX设置剩余存活时间,单位为秒(PX同理,单位为毫秒)。
      • NX,not exists,表示当key不存在时写入,等同于新增。XX表示当key已经存在时写入,等同于修改。
      • GET表示返回旧值。
    • 时间复杂度:O(1)。表示不随 数据库的键数量增长。
    • Example:
    127.0.0.1:6379> set name rose
    OK
    127.0.0.1:6379> set name lily get
    "rose"
    
  • GET:获取key的value,value为string类型。

    • 语法:GET key。key不存在则返回nil。
    • 时间复杂度:O(1)。
    • Example:
    127.0.0.1:6379> get name
    "lily"
    127.0.0.1:6379> get age
    (nil)
    
  • MSET:批量写多个key和string类型的value。

    • 语法:MSET key value [key value ...]
      • 注意:MSET命令没有ex、nx、xx等选项。
    • 时间复杂度:O(n)。n表示键值对的数量。
    • Example:
    127.0.0.1:6379> mset name rose age 22
    OK
    127.0.0.1:6379> get name
    "rose"
    127.0.0.1:6379> get age
    "22"
    
  • MGET:批量读取多个key的value,value为string类型。

    • 语法:MGET key [key ...]
    • 时间复杂度:O(n)。n表示键的数量。
    • Example:
    127.0.0.1:6379> mget name age
    1) "rose"
    2) "22"
    
  • SETEX:写入key和string类型的value,并设置键值对的剩余存活时间。

    • 语法:SETEX key seconds value
      • 等同:SET key value EX seconds
    • 时间复杂度:O(1)。
    • Example:
    127.0.0.1:6379> setex name 10 value
    OK
    127.0.0.1:6379> ttl name
    (integer) 7
    127.0.0.1:6379> ttl name
    (integer) -2
    
  • SETNX:写入key和string类型的value,且key不存在。相当于新增操作。

    • 语法:SETNX key value
    • 时间复杂度:O(1)。
    • Example:
    127.0.0.1:6379> setnx name rose
    (integer) 1
    127.0.0.1:6379> setnx name lily
    (integer) 0
    127.0.0.1:6379> get name
    "rose"
    
  • MSETNX:写入多个key和string类型的value,且key都不存在。相当于批量新增操作。

    • 语法:MSETNX key value [key value ...]
      • 由于redis的命令具有原子性,所以当且仅当所有key都不存在时才执行成功,若其中有一个key存在,则该命令执行失败,所有key、value都写入失败。
    • 时间复杂度:O(n)。n表示键值对的数目。
    • Example:
    127.0.0.1:6379> msetnx name rose age 18
    (integer) 1
    127.0.0.1:6379> msetnx name lily gender female
    (integer) 0
    127.0.0.1:6379> mget name age gender
    1) "rose"
    2) "18"
    3) (nil)
    
  • INCR:value自增1,value为整数字符串。

    • 语法:INCR key
      • 若key不存在,则新增key,value为0,然后再自增1。
    • 时间复杂度:O(1)。
    • Example:
    127.0.0.1:6379> get name
    (nil)
    127.0.0.1:6379> incr name
    (integer) 1
    127.0.0.1:6379> get name
    "1"
    127.0.0.1:6379> incr name
    (integer) 2
    127.0.0.1:6379> get name
    "2"
    
  • INCRBY:value按指定步长自增,value为整数字符串。

    • 语法:INCRBY key increment
      • key不存在,则新增key,value为0,再自增increment。
      • INCRBY key -1 等同于 DECR key
      • INCRBY key -5 等同于 DECRBY key 5
    • 时间复杂度:O(1)。
    • Example:
    127.0.0.1:6379> incrby name 2
    (integer) 2
    127.0.0.1:6379> get name
    "2"
    127.0.0.1:6379> incrby name 10
    (integer) 12
    127.0.0.1:6379> get name
    "12"
    127.0.0.1:6379> incrby name -5
    (integer) 7
    127.0.0.1:6379> get name
    "7"
    
  • INCRBYFLOAT:value按指定步长自增,value为浮点数字符串。

    • 语法:INCRBYFLOAT key increment
      • key不存在,则处理方式与与INCRINCRBY相同。
      • increment是浮点数/整数。
      • key是浮点数/整数字符串。
      • 对比:INCRBY只能处理整数字符串和整数步长;INCRBYFLOAT可以处理整数/浮点数字符串,以及整数/浮点数步长。
    • 时间复杂度:O(1)。
    • Example:
    127.0.0.1:6379> incrbyfloat age 10
    "10"
    127.0.0.1:6379> get age
    "10"
    127.0.0.1:6379> incrbyfloat age -0.5
    "9.5"
    127.0.0.1:6379> get age
    "9.5"
    
  • APPEND:追加写。

    • 语法:APPEND key value
      • 若key不存在,则新增key,并设置value为空字符串,再追加写。相当于SET
    • 时间复杂度:O(1)。
    • EXample:
    127.0.0.1:6379> exists name
    (integer) 0
    127.0.0.1:6379> append name rose
    (integer) 4
    127.0.0.1:6379> get name
    "rose"
    127.0.0.1:6379> append name lily
    (integer) 8
    127.0.0.1:6379> get name
    "roselily"
    
  • GETRANGE:获取子串。

    • 语法:GETRANGE key start end
      • start和end表示字符串下标。值为-1表示最后一个,-2表示倒数第二个。
    • 时间复杂度:O(n)。n表示子串长度。
      • 时间复杂度描述的是算法的执行时间如何随某个(或某些)特定输入规模的增大而增长
      • 讨论时间复杂度之前,必须先明确输入的“规模变量”
    • Example:
    127.0.0.1:6379> getrange name 0 -1
    "roselily"
    127.0.0.1:6379> getrange name 4 -1
    "lily"
    
  • STRLEN:返回字符串值的字节长度。

    • 语法:STRLEN key
    • 时间复杂度:O(1)。
      • 底层结构SDS中显式地存储了字符串的字节长度。
    • Example:
    127.0.0.1:6379> set name rose
    OK
    127.0.0.1:6379> strlen name
    (integer) 4
    127.0.0.1:6379> append name rose
    (integer) 8
    127.0.0.1:6379> strlen name
    (integer) 8
    

应用场景

  • 缓存对象:将对象序列化为json字符串,存储在string类型。
  • 计数器:使用INCR命令实现计数。
  • 分布式锁:SETNX
  • 存储session信息:将session信息序列化为字符串存储在string类型中。
  • 存储小文件:利用二进制安全的特性可以存储任意类型的数据,比如小图标、图片验证码等。

List

简介

  • 本质是双向链表,可正向/反向检索。

  • 特点:

    • 有序。按照插入的顺序构成有序。
    • 元素可重复。

常用命令

  • LPUSH:左端添加元素。

    • 语法:LPUSH key element [element ...]

      • 返回值为列表中的元素个数。
    • 时间复杂度:添加一个元素O(1),添加n个元素O(n)。

    • Example:

    127.0.0.1:6379> lpush stus rose lily
    (integer) 2
    127.0.0.1:6379> lpush stus mary jane
    (integer) 4
    127.0.0.1:6379> lrange stus 0 -1
    1) "jane"
    2) "mary"
    3) "lily"
    4) "rose"
    
  • RPUSH:右端添加元素。

    • 语法:RPUSH key element [element ...]
    • 时间复杂度:O(1)/O(n),n表示元素个数。
    • Example:
    127.0.0.1:6379> rpush names rose may
    (integer) 2
    127.0.0.1:6379> rpush names lily rachel
    (integer) 4
    127.0.0.1:6379> lrange names 0 -1
    1) "rose"
    2) "may"
    3) "lily"
    4) "rachel"
    
  • LPOP:左端弹出元素。

    • 语法:LPOP key [count]

      • count表示移除的元素个数,默认为1。
      • 返回值为移除的元素。
      • 值在键在,值消键亡。
    • 时间复杂度:O(1)/O(n),n是移除的元素数。

    • Example:

    127.0.0.1:6379> lpush name jane lucy daisy lily susan
    (integer) 5
    127.0.0.1:6379> lrange name 0 -1
    1) "susan"
    2) "lily"
    3) "daisy"
    4) "lucy"
    5) "jane"
    127.0.0.1:6379> lpop name 
    "susan"
    127.0.0.1:6379> lpop name 2
    1) "lily"
    2) "daisy"
    127.0.0.1:6379> lrange name 0 -1
    1) "lucy"
    2) "jane"
    
  • RPOP:右端弹出元素。

    • 语法:RPOP key [count]

      • count表示移除的元素个数,默认为1。
      • 返回值为移除的元素。
      • 值在键在,值消键亡。
    • 时间复杂度:O(1)/O(n),n是移除的元素个数。

    • Example:

    127.0.0.1:6379> lrange nums 0 -1
    1) "1"
    2) "2"
    3) "3"
    4) "4"
    5) "5"
    127.0.0.1:6379> rpop nums 
    "5"
    127.0.0.1:6379> rpop nums 2
    1) "4"
    2) "3"
    127.0.0.1:6379> lrange nums 0 -1
    1) "1"
    2) "2"
    127.0.0.1:6379> rpop nums 2
    1) "2"
    2) "1"
    127.0.0.1:6379> exists nums
    (integer) 0
    
  • BLPOP:从左端阻塞式弹出元素。

    • 语法:BLPOP key [key ...] timeout

      • 列表中有值,则弹出;无值,则阻塞连接,直到有值弹出或超时。
      • timeout是阻塞等待的秒数。
      • 返回值为被移除元素的键值。
    • 时间复杂度:O(1)。

    • Example:

    127.0.0.1:6379> lpush name lily rose
    (integer) 2
    127.0.0.1:6379> blpop name 0
    1) "name"
    2) "rose"
    127.0.0.1:6379> blpop name 5
    1) "name"
    2) "lily"
    127.0.0.1:6379> blpop name 5
    (nil)
    (5.06s)
    
  • BRPOP:从右端阻塞式弹出元素。

    • 语法:BRPOP key [key ...] timeout

      • 有值就弹,无值等待。
      • timeout是等待秒数。
      • 返回值为被移除元素的键和值。
    • 时间复杂度:O(1)。

    • Example:

    127.0.0.1:6379> lpush nums 1 2 3
    (integer) 3
    127.0.0.1:6379> lrange nums 0 -1
    1) "3"
    2) "2"
    3) "1"
    127.0.0.1:6379> brpop nums 0
    1) "nums"
    2) "1"
    127.0.0.1:6379> brpop nums 0
    1) "nums"
    2) "2"
    127.0.0.1:6379> brpop nums 0
    1) "nums"
    2) "3"
    127.0.0.1:6379> brpop nums 2
    (nil)
    (2.08s)
    127.0.0.1:6379> exists nums
    (integer) 0
    
  • LRANGE:返回指定下标区间内的元素。

    • 语法:LRANGE key start stop
      • start/stop表示元素下标,左端从0开始。-1表示最后一个元素,-2表示倒数第二个元素。
      • 返回列表中下标区间为[start, stop]的全部元素。
    • 时间复杂度:O(s+n),s表示start的偏移量,n表示返回的元素个数。
    • Example:
    127.0.0.1:6379> rpush nums 1 2 3 4 5
    (integer) 5
    127.0.0.1:6379> lrange nums 0 -1
    1) "1"
    2) "2"
    3) "3"
    4) "4"
    5) "5"
    127.0.0.1:6379> lrange nums 0 -2
    1) "1"
    2) "2"
    3) "3"
    4) "4"
    127.0.0.1:6379> lrange nums 3 -2
    1) "4"
    
  • LLEN:获取列表元素个数。

    • 语法:LLEN key

    • 时间复杂度:O(1)。

      • list的底层数据结构quicklist中直接存储了列表长度。
    • Example:

    127.0.0.1:6379> llen nums
    (integer) 5
    
  • LINSERT:在指定元素之前/后插入新元素。

    • 语法:LINSERT key <BEFORE | AFTER> pivot element

      • before/after表示在pivot之前/之后插入元素。
      • pivot是参照的元素值。
      • element是插入的新元素。
      • 返回值正整数表示插入后的列表长度;返回值为0表示该key不存在;返回值-1表示pivot不存在。
    • 时间复杂度:O(n),n表示检索pivot需要遍历的元素个数。

    • Example:

    127.0.0.1:6379> linsert nums before "2" "1.5"
    (integer) 6
    127.0.0.1:6379> lrange nums 0 -1
    1) "1"
    2) "1.5"
    3) "2"
    4) "3"
    5) "4"
    6) "5"
    127.0.0.1:6379> linsert nums after "4" "4.5"
    (integer) 7
    127.0.0.1:6379> lrange nums 0 -1
    1) "1"
    2) "1.5"
    3) "2"
    4) "3"
    5) "4"
    6) "4.5"
    7) "5"
    
  • LREM:从左向右或从右向左移除count个特定值的元素。

    • 语法:LREM key count element

      • count=0表示移除所有等于element的元素;count>0表示从左向右移除前count个等于element的元素;count<0表示从右向左移除前-count个等于element的元素。
      • 返回值为移除元素的个数。
    • 时间复杂度:O(n),n表示列表长度。

    • Example:

    127.0.0.1:6379> rpush nums 1 2 3 1 1 4 5 1 6
    (integer) 9
    127.0.0.1:6379> lrange nums 0 -1
    1) "1"
    2) "2"
    3) "3"
    4) "1"
    5) "1"
    6) "4"
    7) "5"
    8) "1"
    9) "6"
    127.0.0.1:6379> lrem nums 0 1
    (integer) 4
    127.0.0.1:6379> lrange nums 0 -1
    1) "2"
    2) "3"
    3) "4"
    4) "5"
    5) "6"
    
    
    127.0.0.1:6379> rpush nums2 1 2 3 1 1 4
    (integer) 6
    127.0.0.1:6379> lrange num2 0 -1
    (empty array)
    127.0.0.1:6379> lrem nums2 2 1
    (integer) 2
    127.0.0.1:6379> lrange numsw 0 -1
    (empty array)
    127.0.0.1:6379> lrange nums2 0 -1
    1) "2"
    2) "3"
    3) "1"
    4) "4"
    
    
    127.0.0.1:6379> rpush nums3 1 2 3 1 1 5 6 1
    (integer) 8
    127.0.0.1:6379> lrem nums3 -2 1
    (integer) 2
    127.0.0.1:6379> lrange nums3 0 -1
    1) "1"
    2) "2"
    3) "3"
    4) "1"
    5) "5"
    6) "6"
    
  • LSET:修改指定下标的元素值。

    • 语法:LSET key index element

      • index是要修改元素的下标。
    • 时间复杂度:O(n),n表示index的大小。

    • Example:

    127.0.0.1:6379> rpush nums 1 2 3
    (integer) 3
    127.0.0.1:6379> lset nums 0 1.0
    OK
    127.0.0.1:6379> lset nums -1 3.0
    OK
    127.0.0.1:6379> lset nums -2 2.0
    OK
    127.0.0.1:6379> lrange nums 0 -1
    1) "1.0"
    2) "2.0"
    3) "3.0"
    
  • LINDEX:根据下标查找元素。

    • 语法:LINDEX key index
      • index表示元素下标。左端从0开始。-1 表示最后一个,-2表示倒数第二个。
    • 时间复杂度:O(n),n表示index的大小。
    • Example:
    127.0.0.1:6379> lrange nums 0 -1
    1) "1"
    2) "2"
    3) "3"
    4) "4"
    5) "5"
    127.0.0.1:6379> lindex nums 0
    "1"
    127.0.0.1:6379> lindex nums -1
    "5"
    127.0.0.1:6379> lindex nums 4
    "5"
    127.0.0.1:6379> lindex nums 2
    "3"
    

应用场景

  • 栈:出入同侧。LPUSH+LPOP,或RPUSH+RPOP。
  • 队列:出入异侧。LPUSH+RPOP,或RPUSH+LPOP。
  • 阻塞队列:出入异侧,阻塞弹出。LPUSH+BRPOP,或RPUSH+BLPOP。
  • 消息队列。

HASH

简介

  • value是哈希表,由多对field value组成。

常用命令

  • HSET:在hash中写入<field, value>。

    • 语法:HSET key field value [field value ...]
      • 返回值为写入的field数量。
    • 时间复杂度:O(1)。(如果有多个<field, value>,则为O(n))。
    • Example:
    127.0.0.1:6379> hset h1 f1 v1 f2 v2
    (integer) 2
    127.0.0.1:6379> hget h1 f1
    "v1"
    127.0.0.1:6379> hget h1 f2
    "v2"
    
  • HGET:从hash中获取指定field的value。

    • 语法:HGET key field
    • 时间复杂度:O(1)。
    • Example:
    127.0.0.1:6379> hset h1 f1 v1
    (integer) 1
    127.0.0.1:6379> hget h1 f1
    "v1"
    127.0.0.1:6379> hget h1 f3
    (nil)
    
  • HMSET:在hash中批量写入<field, value>。

    • 语法:HMSET key field value [field value ...]
      • 从4.0版本开始,被HSET代替。
    • 时间复杂度:O(n),n是写入field,value的数量。
    • Example:
    127.0.0.1:6379> hmset h1 f1 v1 f2 v2 f3 v3
    OK
    127.0.0.1:6379> hgetall h1
    1) "f1"
    2) "v1"
    3) "f2"
    4) "v2"
    5) "f3"
    6) "v3"
    
  • HMGET:从hash中读取多个field的value。

    • 语法:HMGET key field [field ...]
    • 时间复杂度:O(n),n为field的数量。
    • Example:
    127.0.0.1:6379> hmget h1 f1 f3
    1) "v1"
    2) "v3"
    
  • HGETALL:获取hash中所有<field, value>。

    • 语法:HGETALL key
    • 时间复杂度:O(n),n表示hash中的字段数量。
    • Example:
    127.0.0.1:6379> hgetall h1
    1) "f1"
    2) "v1"
    3) "f2"
    4) "v2"
    5) "f3"
    6) "v3"
    
  • HKEYS:获取hash中所有field。

    • 语法:HKEYS key
    • 时间复杂度:O(n),n表示hash中的字段数量。
    • Example:
    127.0.0.1:6379> hkeys h1
    1) "f1"
    2) "f2"
    3) "f3"
    
  • HVALS:获取hash中所有value。

    • 语法:HVALS key
    • 时间复杂度:O(n),n表示hash中的字段数量。
    • Example:
    127.0.0.1:6379> hvals h1
    1) "v1"
    2) "v2"
    3) "v3"
    
  • HSETNX:向hash中新增<field, value>。

    • 语法:HSETNX key field value
      • 当且仅当field不存在时才执行成功。
    • 时间复杂度:O(1)。
    • Example:
    127.0.0.1:6379> hgetall h1
    1) "f1"
    2) "v1"
    3) "f2"
    4) "v2"
    5) "f3"
    6) "v3"
    127.0.0.1:6379> hsetnx h1 f1 v11
    (integer) 0
    127.0.0.1:6379> hgetall h1
    1) "f1"
    2) "v1"
    3) "f2"
    4) "v2"
    5) "f3"
    6) "v3"
    127.0.0.1:6379> hsetnx h1 f4 v4
    (integer) 1
    127.0.0.1:6379> hgetall h1
    1) "f1"
    2) "v1"
    3) "f2"
    4) "v2"
    5) "f3"
    6) "v3"
    7) "f4"
    8) "v4"
    
  • HINCRBY:对value按照指定步长自增。

    • 语法:HINCRBY key field increment
      • 返回值为自增后的新值。
    • 时间复杂度:O(1)。
    • Example:
    127.0.0.1:6379> hset h1 f1 5
    (integer) 1
    127.0.0.1:6379> hget h1 f1
    "5"
    127.0.0.1:6379> hincrby h1 f1 5
    (integer) 10
    127.0.0.1:6379> hincrby h1 f1 -2
    (integer) 8
    
  • HEXISTS:判断hash中是否存在某field。

    • 语法:HEXISTS key field
    • 时间复杂度:O(1)。
    • Example:
    127.0.0.1:6379> hexists h1 f1
    (integer) 1
    127.0.0.1:6379> hexists h1 f5
    (integer) 0
    
  • HLEN:返回hash中的字段个数。

    • 语法:HLEN key
    • 时间复杂度:O(1)。
      • ziplist编码格式下,需要遍历整个hash来获取字段总数。但是由于ziplist保存的字段数目有限,所以可以看作常数级时间复杂度。
      • hashtable编码格式下,显式地维护了记录键值对个数的字段。
    • Example:
    127.0.0.1:6379> hset h1 f1 1 f2 2 f3 3 
    (integer) 3
    127.0.0.1:6379> hlen h1
    (integer) 3
    

应用场景

  • 缓存对象:key为对象id,<field, value>存储对象中的字段和值。
    • 相比于string类型缓存对象的优点:可以直接查看或修改某一字段的值,而不需要像string类型那样读取整个json字符串的值。
  • 计数器组合:利用HINCRBY命令可以实现多个计数器。
  • 配置项管理:利用<field, value>存储配置项。
  • 实现可重入的分布式锁:利用HSETNX加锁,key表示锁的名称,field表示持有者id,value表示计数器,记录加锁次数。

Set

简介

  • 集合类型,可看作“只关注key,value为空的哈希表”。
  • 特点:
    • 无序。
    • 元素不可重复。
    • 支持集合运算:并、交、差集。

常用命令

  • SADD:向集合中写入元素。

    • 语法:SADD key member [member ...]
    • 时间复杂度:O(1)。(若批量添加多个元素,则为O(n),n是添加的元素个数。)
    • Example:
    127.0.0.1:6379> sadd s1 1 2 3
    (integer) 3
    127.0.0.1:6379> smembers s1
    1) "1"
    2) "2"
    3) "3"
    
  • SREM:从集合中删除元素。

    • 语法:SREM key member [member ...]
    • 时间复杂度:O(1)。(若批量删除多个元素,则为O(n)。)
    • Example:
    127.0.0.1:6379> smembers s1
    1) "1"
    2) "2"
    3) "3"
    127.0.0.1:6379> srem s1 3
    (integer) 1
    127.0.0.1:6379> smembers s1
    1) "1"
    2) "2"
    
  • SCARD:返回集合元素总数。

    • 语法:SCARD key

      • card是Cardinality(基数)的缩写,是集合论的数学术语,表示集合中元素的数量。
    • 时间复杂度:O(1)。

      • 底层数据结构intset / hashtable中显式地维护了用来记录元素个数的字段。
    • Example:

    127.0.0.1:6379> smembers s1
    1) "1"
    2) "2"
    127.0.0.1:6379> scard s1
    (integer) 2
    
  • SISMEMBER:判断某元素是否存在。

    • 语法:SISMEMBER key member
    • 时间复杂度:O(1)。
    • Example:
    127.0.0.1:6379> smembers s1
    1) "1"
    2) "2"
    127.0.0.1:6379> sismember s1 2
    (integer) 1
    127.0.0.1:6379> sismember s1 3
    (integer) 0
    
  • SMEMBERS:返回集合中所有元素。

    • 语法:SMEMBERS key
    • 时间复杂度:O(n),n表示集合的元素总数。
    • Example:
    127.0.0.1:6379> smembers s1
    1) "1"
    2) "2"
    
  • SUNION:求多个集合的并集。

    • 语法:SUNION key [key ...]
    • 时间复杂度:O(n),n表示所有集合的基数之和。
    • Example:
    127.0.0.1:6379> sadd s1 1 2 3 
    (integer) 3
    127.0.0.1:6379> sadd s2 2 4 5
    (integer) 3
    127.0.0.1:6379> sunion s1 s2
    1) "1"
    2) "2"
    3) "3"
    4) "4"
    5) "5"
    
  • SINTER:求多个集合的交集。

    • 语法:SINTER key [key ...]

    • 时间复杂度:最坏的情况是O(m*n),m表示最小的集合基数,n表示集合的数量。

      • redis的SINTER的计算思路是:找到基数最小的集合,作为基准集合;遍历基准集合中的m个元素,每遍历一个元素,就去其他n-1个集合中查找是否存在该元素,若n-1个集合都存在该元素,则将其放入结果集,若有集合中不存在该元素,则跳出循环,继续处理基准集合的下一个元素。
    • Example:

    127.0.0.1:6379> sadd s1 1 2 3 
    (integer) 3
    127.0.0.1:6379> sadd s2 2 4 5
    (integer) 3
    127.0.0.1:6379> sinter s1 s2
    1) "2"
    
  • SDIFF:求多个集合的差集。

    • 语法:SDIFF key [key ...]

      • SDIFF s1 s2 s3,表示集合s1中存在,s2、s3中不存在的元素集合。
    • 时间复杂度:O(n),n是所有集合的基数之和。

      • redis的SDIFF计算思路是:先求出s2...sn的并集;再求s1和并集的差集:遍历s1中的元素,每遍历一个元素,检查并集中是否也存在该元素。???
    • Example:

    127.0.0.1:6379> sadd s1 1 2 3 4 5
    (integer) 5
    127.0.0.1:6379> sadd s2 2 5 6 
    (integer) 3
    127.0.0.1:6379> sadd s3 3 7
    (integer) 2
    127.0.0.1:6379> sdiff s1 s2 s3
    1) "1"
    2) "4"
    

应用场景

  • 记录文章点赞数:key为文章id,set中记录每一个点赞用户的id,利用set元素的不可重复特性实现去重。最后通过SCARD返回点赞数。
  • 计算共同关注:通过SINTER计算用户的共同关注。

Sorted Set

简介

  • 有序集合。集合中每个元素关联一个分数score,基于score进行排序。
  • 特点:
    • 有序。基于score进行升序排列。
    • 元素不可重复。
    • 支持集合运算:并、交、差集。

常用命令

  • ZADD:向有序集合中写入元素和对应的分数。

    • 语法:ZADD key [NX | XX] [GT | LT] [CH] [INCR] score member [score member...]
      • NX:元素不存在时执行。相当于新增。
      • XX:元素已存在时执行。相当于修改。
      • LT:元素已存在,且新score<旧score时执行。
      • GT:元素已存在,且新score>旧score时执行。
      • score:member对应的分数。
      • member:写入的元素值。
    • 时间复杂度:O(logn),n表示有序集合的元素总数。
      • 底层数据结构跳表,每次插入元素的时间复杂度为O(logn)。
    • Example:
    127.0.0.1:6379> zadd z1 10 rose 
    (integer) 1
    127.0.0.1:6379> zadd z1 30 lily 
    (integer) 1
    127.0.0.1:6379> zrange z1 0 -1
    1) "rose"
    2) "lily"
    
  • ZREM:从有序集合中移除元素。

    • 语法:ZREM key member [member ...]
    • 时间复杂度:O(logn),n表示有序集合的元素总数。(若批量移除多个元素,则O(m*logn),m是移除的元素个数。)
    • Example:
    127.0.0.1:6379> zrange z1 0 -1
    1) "rose"
    2) "lily"
    127.0.0.1:6379> zrem z1 rose
    (integer) 1
    127.0.0.1:6379> zrange z1 0 -1
    1) "lily"
    
  • ZSCORE:查询有序集合中某元素的分数。

    • 语法:ZSCORE key member
    • 时间复杂度:O(1)。
    • Example:
    127.0.0.1:6379> zscore z1 lily
    "30"
    
  • ZCARD:查询有序集合的元素总数。

    • 语法:ZCARD key
    • 时间复杂度:O(1)。
    • Example:
    127.0.0.1:6379> zadd z2 1 one 2 two 5 five
    (integer) 3
    127.0.0.1:6379> zcard z2
    (integer) 3
    
  • ZCOUNT:返回指定分数区间内的元素数目。

    • 语法:ZCOUNT key min max
    • 时间复杂度:O(logn),n表示有序集合的元素总数。
    • Example:
    127.0.0.1:6379> zadd z2 1 one 2 two 5 five
    (integer) 3
    127.0.0.1:6379> zcount z2 2 5
    (integer) 2
    127.0.0.1:6379> zcount z2 -inf +inf
    (integer) 3
    
  • ZINCRBY:增加某元素的分数。

    • 语法:ZINCRBY key increment member
    • 时间复杂度:O(logn),n表示有序集合的元素总数。
    • Example:
    127.0.0.1:6379> zadd z1 1 one 2 two 3 three
    (integer) 3
    127.0.0.1:6379> zincrby z1 3 one
    "4"
    127.0.0.1:6379> zrange z1 0 -1 withscores
    1) "two"
    2) "2"
    3) "three"
    4) "3"
    5) "one"
    6) "4"
    
  • ZRANGE:按照下标区间返回元素。

    • 语法:ZRANGE key start stop [BYSCORE | BYLEX] [REV] [LIMIT offset count] [WITHSCORES]
      • BYSCORE:按照分数区间返回元素。
      • REV:逆序。
      • WITHSCORES:返回值携带分数。
    • 时间复杂度:O(logn+m),n表示有序集合的元素总数,m表示返回的元素个数。
    • Example:
    127.0.0.1:6379> zadd z1 1 one 2 two 3 three 4 four 5 five 
    (integer) 5
    127.0.0.1:6379> zrange z1 0 -1
    1) "one"
    2) "two"
    3) "three"
    4) "four"
    5) "five"
    127.0.0.1:6379> zrange z1 0 -1 rev
    1) "five"
    2) "four"
    3) "three"
    4) "two"
    5) "one"
    127.0.0.1:6379> zrange z1 0 1 rev
    1) "five"
    2) "four"
    127.0.0.1:6379> zrange z1 3 5 byscore 
    1) "three"
    2) "four"
    3) "five"
    
  • ZUNION/ZINTER/ZDIFF:并、交、差集。

应用场景

  • 排行榜:排列对象作为member,排列依据作为score。
  • 范围查询。
  • 唯一性约束+排序。
posted @ 2025-06-17 16:24  electrwlr  阅读(51)  评论(0)    收藏  举报