关于redis数据类型操作的应用场景及时间复杂度
- String类型命令时间复杂度和应用场景
- string类型高时间复杂度的命令汇总
- List类型的命令的时间复杂度和应用场景
- 列表数据类型命令时间复杂度高的命令
- SET类型的基本命令时间复杂度及应用场景
- ZSET类型的命令的时间复杂度及应用场景
- HASH类型命令及其时间复杂度
String类型命令时间复杂度和应用场景
- set key value 时间复杂度: O(1)
- SETNX key value 时间复杂度: O(1)
SetNX用来实现分布式锁
- SETEX key seconds value 时间复杂度: O(1)
- PSETEX key milliseconds value 时间复杂度: O(1)
- GET key 时间复杂度: O(1)
- GETSET key value 时间复杂度: O(1)
- STRLEN key 时间复杂度: O(1)
- APPEND key value 平摊O(1)
- SETRANGE key offset value 时间复杂度:对于长度较短的字符串,命令的平摊复杂度O(1);对于长度较大的字符串,命令的复杂度为 O(M) ,其中 M 为 value 的长度。
- GETRANGE key start end 时间复杂度: O(N),其中 N 为被返回的字符串的长度。
- INCR key 时间复杂度: O(1)
INCR 系列的命令可以用来实现计数器的功能
- INCRBY key increment 时间复杂度: O(1)
- INCRBYFLOAT key increment 时间复杂度: O(1)
- DECR key 时间复杂度: O(1)
- MSET key value [key value …] 时间复杂度: O(N),其中 N 为被设置的键数量。
- MSETNX key value [key value …] 时间复杂度: O(N), 其中 N 为被设置的键数量。
- MGET key [key …] 时间复杂度: O(N) ,其中 N 为给定键的数量。
string类型高时间复杂度的命令汇总
m系列的命令 和 getrange 命令 以及一定情况下的setrange 命令
List类型的命令的时间复杂度和应用场景
- LPUSH key value [value …] 时间复杂度: O(1)
- LPUSHX key value 时间复杂度: O(1)
- RPUSH key value [value …] 时间复杂度: O(1)
- RPUSHX key value 时间复杂度: O(1)
- LPOP key 时间复杂度: O(1)
- RPOP key 时间复杂度: O(1)
- RPOPLPUSH source destination 时间复杂度: O(1)
- LREM key count value 时间复杂度: O(N)
- LLEN key 时间复杂度: O(1)
- LINDEX key index 时间复杂度: O(N)
- LINSERT key BEFORE|AFTER pivot value 时间复杂度: O(N), N 为寻找 pivot 过程中经过的元素数量。
- LSET key index value 时间复杂度:对头元素或尾元素进行 LSET 操作,复杂度为 O(1)。其他情况下,为 O(N), N 为列表的长度。
- LRANGE key start stop 时间复杂度: O(S+N), S 为偏移量 start , N 为指定区间内元素的数量。
- LTRIM key start stop 时间复杂度为 O(N) ,N为删除的元素
LTRIM 命令通常和 LPUSH key value [value …] 命令或 RPUSH key value [value …] 命令配合使用,举个例子:LPUSH log newest_log
LTRIM log 0 99
这个例子模拟了一个日志程序,每次将最新日志 newest_log 放到 log 列表中,并且只保留最新的 100 项。注意当这样使用 LTRIM 命令时,时间复杂度是O(1),因为平均情况下,每次只有一个元素被移除。
- BLPOP key [key …] timeout 时间复杂度: O(1)
阻塞队列
有时候,为了等待一个新元素到达数据中,需要使用轮询的方式对数据进行探查。
另一种更好的方式是,使用系统提供的阻塞原语,在新元素到达时立即进行处理,而新元素还没到达时,就一直阻塞住,避免轮询占用资源。
对于 Redis ,我们似乎需要一个阻塞版的 SPOP key 命令,但实际上,使用 BLPOP 或者 BRPOP key [key …] timeout 就能很好地解决这个问题。
- BRPOPLPUSH source destination timeout 时间复杂度: O(1)
安全队列
Redis的列表经常被用作队列(queue),用于在不同程序之间有序地交换消息(message)。一个客户端通过 LPUSH key value [value …] 命令将消息放入队列中,而另一个客户端通过 RPOP key 或者 BRPOP key [key …] timeout 命令取出队列中等待时间最长的消息。不幸的是,上面的队列方法是『不安全』的,因为在这个过程中,一个客户端可能在取出一个消息之后崩溃,而未处理完的消息也就因此丢失。使用 RPOPLPUSH 命令(或者它的阻塞版本 BRPOPLPUSH source destination timeout )可以解决这个问题:因为它不仅返回一个消息,同时还将这个消息添加到另一个备份列表当中,如果一切正常的话,当一个客户端完成某个消息的处理之后,可以用 LREM key count value 命令将这个消息从备份表删除。最后,还可以添加一个客户端专门用于监视备份表,它自动地将超过一定处理时限的消息重新放入队列中去(负责处理该消息的客户端可能已经崩溃),这样就不会丢失任何消息了。
循环队列
通过使用相同的 key 作为 RPOPLPUSH 命令的两个参数,客户端可以用一个接一个地获取列表元素的方式,取得列表的所有元素,而不必像 LRANGE key start stop 命令那样一下子将所有列表元素都从服务器传送到客户端中(两种方式的总复杂度都是 O(N))。
以上的模式甚至在以下的两个情况下也能正常工作:有多个客户端同时对同一个列表进行旋转(rotating),它们获取不同的元素,直到所有元素都被读取完,之后又从头开始。
有客户端在向列表尾部(右边)添加新元素。这个模式使得我们可以很容易实现这样一类系统:有 N 个客户端,需要连续不断地对一些元素进行处理,而且处理的过程必须尽可能地快。一个典型的例子就是服务器的监控程序:它们需要在尽可能短的时间内,并行地检查一组网站,确保它们的可访问性。
这个模式使得我们可以很容易实现这样一类系统:有 N 个客户端,需要连续不断地对一些元素进行处理,而且处理的过程必须尽可能地快。一个典型的例子就是服务器的监控程序:它们需要在尽可能短的时间内,并行地检查一组网站,确保它们的可访问性。注意,使用这个模式的客户端是易于扩展(scala)且安全(reliable)的,因为就算接收到元素的客户端失败,元素还是保存在列表里面,不会丢失,等到下个迭代来临的时候,别的客户端又可以继续处理这些元素了。
列表数据类型命令时间复杂度高的命令
LREM key count value 时间复杂度: O(N)
LTRIM key start stop 时间复杂度为 O(N) ,N为删除的元素
LSET 操作,复杂度为 O(1)。其他情况下,为 O(N), N 为列表的长度。
LRANGE key start stop 时间复杂度: O(S+N), S 为偏移量 start , N 为指定区间内元素的数量。
LINDEX key index 时间复杂度: O(N)
SET类型的基本命令时间复杂度及应用场景
- SADD key member [member …] 时间复杂度: O(N), N 是被添加的元素的数量。
- SISMEMBER key member 时间复杂度: O(1)
- SPOP key 时间复杂度: O(1)
- SRANDMEMBER key [count] 时间复杂度: 只提供 key 参数时为 O(1) 。如果提供了 count 参数,那么为 O(N) ,N 为返回数组的元素个数。
- SREM key member [member …] 时间复杂度: O(N), N 为给定 member 元素的数量。
- SMOVE source destination member 时间复杂度: O(1)
- SCARD key 时间复杂度: O(1)
- SMEMBERS key 时间复杂度: O(N), N 为集合的基数。
- SINTER key [key …] 时间复杂度: O(N * M), N 为给定集合当中基数最小的集合, M 为给定集合的个数。
实现关注模型,可能认识的人
- SINTERSTORE destination key [key …] 时间复杂度: O(N * M), N 为给定集合当中基数最小的集合, M 为给定集合的个数。
- SUNION key [key …] 时间复杂度: O(N), N 是所有给定集合的成员数量之和。
- SUNIONSTORE destination key [key …] 时间复杂度: O(N), N 是所有给定集合的成员数量之和。
- SDIFF key [key …] 时间复杂度: O(N), N 是所有给定集合的成员数量之和。
ZSET类型的命令的时间复杂度及应用场景
redis的zset天生是用来做排行榜的、好友列表, 去重, 历史记录等业务需求。
- ZADD key score member [[score member] [score member] …] 时间复杂度: O(M*log(N)), N 是有序集的基数, M 为成功添加的新成员的数量。
- ZSCORE key member 时间复杂度: O(1)
- ZINCRBY key increment member 时间复杂度: O(log(N))
- ZCOUNT key min max 时间复杂度: O(log(N)), N 为有序集的基数。
- ZRANGE key start stop [WITHSCORES] 时间复杂度: O(log(N)+M), N 为有序集的基数,而 M 为结果集的基数。
- ZREVRANGE key start stop [WITHSCORES] 时间复杂度: O(log(N)+M), N 为有序集的基数,而 M 为结果集的基数。
- ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count] 时间复杂度: O(log(N)+M), N 为有序集的基数, M 为被结果集的基数。
- ZRANK key member 时间复杂度: O(log(N))
- ZREVRANK key member 时间复杂度: O(log(N))
- ZREM key member [member …] 时间复杂度: O(M*log(N)), N 为有序集的基数, M 为被成功移除的成员的数量。
- ZREMRANGEBYRANK key start stop 时间复杂度: O(log(N)+M), N 为有序集的基数,而 M 为被移除成员的数量。
- ZREMRANGEBYSCORE key min max 时间复杂度: O(log(N)+M), N 为有序集的基数,而 M 为被移除成员的数量。
- ZRANGEBYLEX key min max [LIMIT offset count] 时间复杂度:O(log(N)+M), 其中 N 为有序集合的元素数量, 而 M 则是命令返回的元素数量 命令会使用 C 语言的 memcmp() 函数, 对集合中的每个成员进行逐个字节的对比(byte-by-byte compare), 并按照从低到高的顺序, 返回排序后的集合成员。 如果两个字符串有一部分内容是相同的话, 那么命令会认为较长的字符串比较短的字符串要大
- ZLEXCOUNT key min max 时间复杂度: O(log(N)),其中 N 为有序集合包含的元素数量。
- ZREMRANGEBYLEX key min max 时间复杂度: O(log(N)+M), 其中 N 为有序集合的元素数量, 而 M 则为被移除的元素数量。
HASH类型命令及其时间复杂度
- HSET hash field value 时间复杂度: O(1)
- HSETNX hash field value 时间复杂度: O(1)
- HGET hash field 时间复杂度: O(1)
- HEXISTS hash field 时间复杂度: O(1)
- HDEL key field [field …] 时间复杂度:O(N), N 为要删除的域的数量。
- HLEN key 时间复杂度:O(1)
- HSTRLEN key field 时间复杂度:O(1)
- HINCRBY key field increment 时间复杂度:O(1)
- HMSET key field value [field value …] 时间复杂度:O(N),N 为 field-value 对的数量。
- HMGET key field [field …] 时间复杂度:O(N), N 为给定域的数量。
- HKEYS key 时间复杂度:O(N), N 为哈希表的大小。
- HVALS key 时间复杂度:O(N)
- HGETALL key 时间复杂度:O(N)