自1.0.0起可用。时间复杂度: O(N),
N
为数据库中key
的数量。web
查找全部符合给定模式 pattern
的 key
。redis
KEYS *
匹配数据库中全部 key
。算法
KEYS h?llo
匹配 hello
, hallo
和 hxllo
等。shell
KEYS h*llo
匹配 hllo
和 heeeeello
等。数据库
KEYS h[ae]llo
匹配 hello
和 hallo
,但不匹配 hillo
。数组
特殊符号用 \
隔开安全
KEYS
的速度很是快,但在一个大的数据库中使用它仍然可能形成性能问题,若是你须要从一个数据集中查找特定的 key
,你最好仍是用 Redis 的集合结构 (set)来代替。服务器
符合给定模式的 key
列表。网络
coderknock> KEYS * 1) "name:45" 2) "like_blog_num" 3) "user:3" 4) "40Key" 5) "test" 6) "coderknockCounter" 7) "user:45" 8) "str" 9) "strHash" 10) "39Key" 11) "testChinese" 12) "user:5" 13) "intKey" 14) "embstrKey" 15) "map" 16) "user:34" coderknock> KEYS user:* 1) "user:3" 2) "user:45" 3) "user:5" 4) "user:34" coderknock> KEYS [34][09]Key 1) "40Key" 2) "39Key" coderknock> KEYS user:[3]? 1) "user:34" coderknock> KEYS user:[35] 1) "user:3" 2) "user:5" coderknock> KEYS user:[3]* 1) "user:3" 2) "user:34" coderknock> KEYS *Key 1) "40Key" 2) "39Key" 3) "intKey" 4) "embstrKey"
自1.0.0起可用。时间复杂度: O(1)。数据结构
返回当前数据库的 key
的数量。
当前数据库的 key
的数量。
coderknock> DBSIZE (integer) 16 coderknock> DBSIZE (integer) 16 coderknock> DBSIZE (integer) 16 # 添加一个 key coderknock> SET addKey name coderknock> DBSIZE (integer) 17
DBSIZE
命令在计算键总数时不会遍历全部键,而是直接获取 Redis 内置的键总数变量,因此 DBSIZE
命令的时间复杂度是 O(1)。而 KEYS
命令会遍历全部键,因此它的时间复杂度是 O(n),当 Redis 保存了大量键时,线上环境最好禁止使用 KEYS
。
自1.0.0起可用。时间复杂度: O(1)。
key
检查给定 key
是否存在。
若 key
存在,返回存在的 key
的个数,不然返回 0
。
coderknock> EXISTS addKey (integer) 1 coderknock> EXISTS a (integer) 0 # 同时查询多个 coderknock> EXISTS addKey user:3 user:5 a embstrKey (integer) 4
自1.0.0起可用。时间复杂度: O(N),
N
为被删除的key
的数量。删除单个字符串类型的
key
,时间复杂度为O(1)。删除单个列表、集合、有序集合或哈希表类型的
key
,时间复杂度为O(M),M
为以上数据结构内的元素数量。
删除给定的一个或多个 key
。
不存在的 key
会被忽略。
DEL 是一个通用命令,不管值是什么数据结构类型,DEL 命令均可以将其删除
被删除 key
的数量。
coderknock> HGETALL user:5 1) "name" 2) "coverSanchan" 3) "website" 4) "https://www.coderknock.com" 5) "user" 6) "sanchan" coderknock> DEL user:5 (integer) 1 coderknock> DEL user:5 (integer) 0
自1.0.0起可用。时间复杂度: O(1)
为给定 key
设置生存时间,当 key
过时时(生存时间为 0
),它会被自动删除。
在 Redis 中,带有生存时间的 key
被称为『易失的』(volatile)。
生存时间能够经过使用 DEL
命令来删除整个 key
来移除,或者被 SET
和 GETSET
命令覆写(overwrite),这意味着,若是一个命令只是修改(alter)一个带生存时间的 key
的值而不是用一个新的 key
值来代替(replace)它的话,那么生存时间不会被改变。
好比说,对一个 key
执行 INCR
命令,对一个列表进行 LPUSH
命令,或者对一个哈希表执行 HSET
命令,这类操做都不会修改 key
自己的生存时间。
另外一方面,若是使用 RENAME
对一个 key
进行更名,那么更名后的 key
的生存时间和更名前同样。
RENAME
命令的另外一种多是,尝试将一个带生存时间的 key
更名成另外一个带生存时间的 another_key
,这时旧的 another_key
(以及它的生存时间)会被删除,而后旧的 key
会更名为 another_key
,所以,新的 another_key
的生存时间也和本来的 key
同样。
使用 PERSIST
命令能够在不删除 key
的状况下,移除 key
的生存时间,让 key
从新成为一个『持久的』(persistent) key
。
更新生存时间
能够对一个已经带有生存时间的 key
执行 EXPIRE
命令,新指定的生存时间会取代旧的生存时间。
过时时间的精确度
在 Redis 2.4 版本中,过时时间的延迟在 1 秒钟以内 —— 也便是,就算 key
已通过期,但它仍是可能在过时以后一秒钟以内被访问到,而在新的 Redis 2.6 版本中,延迟被下降到 1 毫秒以内。
Redis 2.1.3 以前的不一样之处
在 Redis 2.1.3 以前的版本中,修改一个带有生存时间的 key
会致使整个 key
被删除,这一行为是受当时复制(replication)层的限制而做出的,如今这一限制已经被修复。
设置成功返回 1
。
当 key
不存在或者不能为 key
设置生存时间时(好比在低于 2.1.3 版本的 Redis 中你尝试更新 key
的生存时间),返回 0
。
redis> SET cache_website "www.coderknock.com" OK redis> EXPIRE cache_website 30 # 设置过时时间为 30 秒 (integer) 1 redis> TTL cache_website # 查看剩余生存时间 (integer) 23 redis> EXPIRE cache_website 30000 # 更新过时时间 (integer) 1 redis> TTL cache_website (integer) 29996 # 在 SET 命令中也能够直接 设置过时时间【SET 命令在 《Redis 字符串》中会讲解】 coderknock> SET cache_website "www.coderknock.com" EX 30 OK coderknock> TTL cache_website (integer) 13 # 30 秒后该键被删除 coderknock> EXISTS cache_website (integer) 0
自1.0.0起可用。时间复杂度: O(1)
以秒为单位,返回给定 key
的剩余生存时间(TTL, time to live)。
当 key
不存在时,返回 -2
。
当 key
存在但没有设置剩余生存时间时,返回 -1
。
不然,以秒为单位,返回 key
的剩余生存时间。
在 Redis 2.8 之前,当 key
不存在,或者 key
没有设置剩余生存时间时,命令都返回 -1
。
#TTL 正常使用在上面一个命令中已经有示例,下面演示一个对不存在 key 使用的状况以及对没有设置过时时间可使用的状况 # 不存在 key coderknock> TTL cache_website (integer) -2 # 存在可是未设置过时时间的 key coderknock> TTL user:3 (integer) -1
TYPE
自1.0.0起可用。时间复杂度: O(1)
返回 key
所储存的值的类型。
none
(key不存在)
string
(字符串)
list
(列表)
set
(集合)
zset
(有序集)
hash
(哈希表)
# 哈希 coderknock> TYPE user:3 hash # 不存在 coderknock> TYPE a none # 字符串 coderknock> TYPE embstrKey string
SCAN
自2.8.0起可用。时间复杂度: 增量式迭代命令每次执行的复杂度为 O(1) , 对数据集进行一次完整迭代的复杂度为 O(N), 其中
N
为数据集中的元素数量。
SCAN
命令及其相关的 SSCAN
命令、 HSCAN
命令和 ZSCAN
命令都用于增量地迭代(incrementally iterate)一集元素(a collection of elements):
SCAN
命令用于迭代当前数据库中的数据库键。SSCAN
命令用于迭代集合键中的元素。HSCAN
命令用于迭代哈希键中的键值对。ZSCAN
命令用于迭代有序集合中的元素(包括元素成员和元素分值)。以上列出的四个命令都支持增量式迭代, 它们每次执行都只会返回少许元素, 因此这些命令能够用于生产环境, 而不会出现像 KEYS
命令、 SMEMBERS
命令带来的问题 —— 当 KEYS
命令被用于处理一个大的数据库时, 又或者 SMEMBERS
命令被用于处理一个大的集合键时, 它们可能会阻塞服务器达数秒之久。
不过, 增量式迭代命令也不是没有缺点的: 举个例子, 使用 SMEMBERS
命令能够返回集合键当前包含的全部元素, 可是对于 SCAN
这类增量式迭代命令来讲, 由于在对键进行增量式迭代的过程当中, 键可能会被修改, 因此增量式迭代命令只能对被返回的元素提供有限的保证 (offer limited guarantees about the returned elements)。
由于 SCAN
、 SSCAN
、 HSCAN
和 ZSCAN
四个命令的工做方式都很是类似, 因此这个文档会一并介绍这四个命令, 可是要记住:
SSCAN
命令、 HSCAN
命令和 ZSCAN
命令的第一个参数老是一个数据库键。SCAN
命令则不须要在第一个参数提供任何数据库键 —— 由于它迭代的是当前数据库中的全部数据库键。SCAN
命令是一个基于游标的迭代器(cursor based iterator): SCAN
命令每次被调用以后, 都会向用户返回一个新的游标, 用户在下次迭代时须要使用这个新游标做为 SCAN
命令的游标参数, 以此来延续以前的迭代过程。
当 SCAN
命令的游标参数被设置为 0
时, 服务器将开始一次新的迭代, 而当服务器向用户返回值为 0
的游标时, 表示迭代已结束。
SCAN
命令的迭代过程示例:coderknock> SCAN 0 1) "13" # 这个为下一个 SCAN 使用的 cursor 2) 1) "name:45" 2) "coderknockCounter" 3) "intKey" 4) "addKey" 5) "like_blog_num" 6) "map" 7) "str" 8) "user:45" 9) "40Key" 10) "user:3" coderknock> SCAN 13 1) "0" 2) 1) "embstrKey" 2) "testChinese" 3) "strHash" 4) "39Key" 5) "test" 6) "user:34"
在上面这个例子中, 第一次迭代使用 0
做为游标, 表示开始一次新的迭代。
第二次迭代使用的是第一次迭代时返回的游标, 也便是命令回复第一个元素的值 —— 13
。
从上面的示例能够看到, SCAN
命令的回复是一个包含两个元素的数组, 第一个数组元素是用于进行下一次迭代的新游标, 而第二个数组元素则是一个数组, 这个数组中包含了全部被迭代的元素。
在第二次调用 SCAN
命令时, 命令返回了游标 0
, 这表示迭代已经结束, 整个数据集(collection)已经被完整遍历过了。
以 0
做为游标开始一次新的迭代, 一直调用 SCAN
命令, 直到命令返回游标 0
, 咱们称这个过程为一次完整遍历(full iteration)。
SCAN
命令, 以及其余增量式迭代命令, 在进行完整遍历的状况下能够为用户带来如下保证: 从完整遍历开始直到完整遍历结束期间, 一直存在于数据集内的全部元素都会被完整遍历返回; 这意味着, 若是有一个元素, 它从遍历开始直到遍历结束期间都存在于被遍历的数据集当中, 那么 SCAN
命令总会在某次迭代中将这个元素返回给用户。
然而由于增量式命令仅仅使用游标来记录迭代状态, 因此这些命令带有如下缺点:
增量式迭代命令并不保证每次执行都返回某个给定数量的元素。
增量式命令甚至可能会返回零个元素, 但只要命令返回的游标不是 0
, 应用程序就不该该将迭代视做结束。
不过命令返回的元素数量老是符合必定规则的, 在实际中:
最后, 用户能够经过增量式迭代命令提供的 COUNT
选项来指定每次迭代返回元素的最大值。
虽然增量式迭代命令不保证每次迭代所返回的元素数量, 但咱们可使用 COUNT
选项, 对命令的行为进行必定程度上的调整。
基本上, COUNT
选项的做用就是让用户告知迭代命令, 在每次迭代中应该从数据集里返回多少元素。
虽然 COUNT
选项只是对增量式迭代命令的一种提示(hint), 可是在大多数状况下, 这种提示都是有效的。
COUNT
参数的默认值为 10
。MATCH
选项, 那么命令返回的元素数量一般和 COUNT
选项指定的同样, 或者比 COUNT
选项指定的数量稍多一些。COUNT
选项指定的值, 在第一次迭代就将数据集包含的全部元素都返回给用户。并不是每次迭代都要使用相同的 COUNT
值。
用户能够在每次迭代中按本身的须要随意改变 COUNT
值, 只要记得将上次迭代返回的游标用到下次迭代里面就能够了。
coderknock> SCAN 0 COUNT 20 1) "0" 2) 1) "name:45" 2) "coderknockCounter" 3) "intKey" 4) "addKey" 5) "like_blog_num" 6) "map" 7) "str" 8) "user:45" 9) "40Key" 10) "user:3" 11) "embstrKey" 12) "testChinese" 13) "strHash" 14) "39Key" 15) "test" 16) "user:34" coderknock> SCAN 0 COUNT 5 1) "10" 2) 1) "name:45" 2) "coderknockCounter" 3) "intKey" 4) "addKey" 5) "like_blog_num" coderknock> SCAN 10 1) "15" 2) 1) "map" 2) "str" 3) "user:45" 4) "40Key" 5) "user:3" 6) "embstrKey" 7) "testChinese" 8) "strHash" 9) "39Key" 10) "test" coderknock> SCAN 15 1) "0" 2) 1) "user:34"
和 KEYS
命令同样, 增量式迭代命令也能够经过提供一个 glob 风格的模式参数, 让命令只返回和给定模式相匹配的元素, 这一点能够经过在执行增量式迭代命令时, 经过给定 MATCH <pattern>
参数来实现。
如下是一个使用 MATCH
选项进行迭代的示例:
coderknock> SADD test 1 2 3 4 11 12 13 14 a ab abc abcd (integer) 12 coderknock> SSCAN test 0 MATCH ab* 1) "3" 2) 1) "abcd" 2) "abc" coderknock> SSCAN test 3 MATCH ab* 1) "0" 2) 1) "ab" # 下面的语句说明要注意 调用 cursor 时 可选项一致,否则获取的数据没有意义 coderknock> SSCAN test 3 1) "0" 2) 1) "ab" 2) "12" coderknock>
须要注意的是, 对元素的模式匹配工做是在命令从数据集中取出元素以后, 向客户端返回元素以前的这段时间内进行的, 因此若是被迭代的数据集中只有少许元素和模式相匹配, 那么迭代命令或许会在屡次执行中都不返回任何元素。
如下是这种状况的一个例子:
coderknock> keys * 1) "name:45" 2) "addKey" 3) "40Key" 4) "coderknockCounter" 5) "testChinese" 6) "strHash" 7) "embstrKey" 8) "map" 9) "like_blog_num" 10) "user:3" 11) "test" 12) "str" 13) "user:45" 14) "39Key" 15) "intKey" 16) "user:34" # 可选项的关键字不能输入错误,不然会报错 coderknock> SCAN 0 MACH em (error) ERR syntax error coderknock> SCAN 0 MATCH em 1) "13" 2) (empty list or set) coderknock> SCAN 13 MATCH 5 1) "0" 2) (empty list or set)
如你所见, 以上的大部分迭代都不返回任何元素。
在同一时间, 能够有任意多个客户端对同一数据集进行迭代, 客户端每次执行迭代都须要传入一个游标, 并在迭代执行以后得到一个新的游标, 而这个游标就包含了迭代的全部状态, 所以, 服务器无须为迭代记录任何状态。
由于迭代的全部状态都保存在游标里面, 而服务器无须为迭代保存任何状态, 因此客户端能够在中途中止一个迭代, 而无须对服务器进行任何通知。
即便有任意数量的迭代在中途中止, 也不会产生任何问题。
使用间断的(broken)、负数、超出范围或者其余非正常的游标来执行增量式迭代并不会形成服务器崩溃, 但可能会让命令产生未定义的行为。
未定义行为指的是, 增量式命令对返回值所作的保证可能会再也不为真。
只有两种游标是合法的:
0
。增量式迭代命令所使用的算法只保证在数据集的大小有界(bounded)的状况下, 迭代才会中止, 换句话说, 若是被迭代数据集的大小不断地增加的话, 增量式迭代命令可能永远也没法完成一次完整迭代。
从直觉上能够看出, 当一个数据集不断地变大时, 想要访问这个数据集中的全部元素就须要作愈来愈多的工做, 可否结束一个迭代取决于用户执行迭代的速度是否比数据集增加的速度更快。
返回值:
SCAN
命令、SSCAN
命令、HSCAN
命令和ZSCAN
命令都返回一个包含两个元素的 multi-bulk 回复: 回复的第一个元素是字符串表示的无符号 64 位整数(游标), 回复的第二个元素是另外一个 multi-bulk 回复, 这个 multi-bulk 回复包含了本次被迭代的元素。
SCAN
命令返回的每一个元素都是一个数据库键。
SSCAN
命令返回的每一个元素都是一个集合成员。
HSCAN
命令返回的每一个元素都是一个键值对,一个键值对由一个键和一个值组成。
ZSCAN
命令返回的每一个元素都是一个有序集合元素,一个有序集合元素由一个成员(member)和一个分值(score)组成。
字符串是一种最基本的Redis值类型。key
都是字符串类型,其余几种数据结构都是在字符串类型的基础上构建的。Redis字符串是二进制安全的,这意味着一个Redis字符串能包含任意类型的数据,例如: 一张JPEG格式的图片或者一个序列化的 Ruby 对象等。
一个字符串类型的值最多能存储 512M 字节的内容。
字符串类型的值实际上能够如下几种:
你能够用Redis字符串作许多有趣的事,例如你能够:
INCR
命令簇(INCR
DECR
INCRBY
)来把字符串看成原子计数器使用。APPEND
命令在字符串后添加内容。GETRANGE
和 SETRANGE
的随机访问向量。GETBIT
和 SETBIT
建立一个Redis支持的 Bloom 过滤器。本系列教程后续会有 字符串 专题会对经常使用命令以及场景进行介绍
Redis 列表是简单的字符串列表,按照插入顺序排序。 你能够添加一个元素到列表的头部(左边)或者尾部(右边)。
LPUSH
命令插入一个新元素到列表头部,而 RPUSH
命令 插入一个新元素到列表的尾部。当 对一个空 key
执行其中某个命令时,将会建立一个新表。 相似的,若是一个操做要清空列表,那么 key
会从对应的 key
空间删除。这是个很是便利的语义, 由于若是使用一个不存在的 key
做为参数,全部的列表命令都会像在对一个空表操做同样。
一个列表最多能够包含2 ^ 32 - 1个元素(4294967295,每一个表超过40亿个元素)。
从时间复杂度的角度来看,Redis 列表主要的特性就是支持时间常数的 插入和靠近头尾部元素的删除,即便是须要插入上百万的条目。 访问列表两端的元素是很是快的,但若是你试着访问一个很是大 的列表的中间元素仍然是十分慢的,由于那是一个时间复杂度为 O(N) 的操做。
你能够用 Redis 列表作许多有趣的事,例如你能够:
LPUSH
去添加新的元素到用户时间线中,使用 LRANGE
去检索一些最近插入的条目。LPUSH
和 LTRIM
去建立一个永远不会超过指定元素数目的列表并同时记住最后的 N 个元素。BLPOP
这样的阻塞命令。请查看全部可用的列表操做命令获取更多的信息。本系列教程后续会有 列表 专题会对经常使用命令以及场景进行介绍
Redis 集合是一个无序的字符串合集。你能够以O(1) 的时间复杂度(不管集合中有多少元素时间复杂度都为常量)完成 添加,删除以及测试元素是否存在的操做。
Redis 集合有着不容许相同成员存在的优秀特性。向集合中屡次添加同一元素,在集合中最终只会存在一个此元素。实际上这就意味着,在添加元素前,你并不须要事先进行检验此元素是否已经存在的操做。
一个 Redis 列表十分有趣的事是,它们支持一些服务端的命令从现有的集合出发去进行集合运算。 因此你能够在很短的时间内完成合并(union),求交(intersection), 找出不一样元素的操做。
一个集合最多能够包含2 ^ 32 - 1个元素(4294967295,每一个集合超过40亿个元素)。
你能够用 Redis 集合作不少有趣的事,例如你能够:
SADD
命令把全部拥有 tag 的对象的全部 ID 添加进集合,这样来表示这个特定的 tag 。若是你想要同时有3个不一样 tag 的全部对象的全部 ID ,那么你须要使用 SINTER
。SPOP
或者 SRANDMEMBER
命令随机地获取元素。本系列教程后续会有 集合 专题会对经常使用命令以及场景进行介绍
Redis 有序集合和 Redis 集合相似,是不包含 相同字符串的合集。它们的差异是,每一个有序集合 的成员都关联着一个评分,这个评分用于把有序集 合中的成员按最低分到最高分排列。
使用有序集合,你能够很是快地(O(log(N)))完成添加,删除和更新元素的操做。 由于元素是在插入时就排好序的,因此很快地经过评分(score)或者 位次(position)得到一个范围的元素。 访问有序集合的中间元素一样也是很是快的,所以你可使用有序集合做为一个没用重复成员的智能列表。 在这个列表中, 你能够轻易地访问任何你须要的东西: 有序的元素,快速的存在性测试,快速访问集合中间元素!
简而言之,使用有序集合你能够很好地完成 不少在其余数据库中难以实现的任务。
使用有序集合你能够:
ZADD
来更新它。你能够用 ZRANGE
轻松地获取排名靠前的用户, 你也能够提供一个用户名,而后用 ZRANK
取他在排行榜中的名次。 同时使用 ZRANK
和 ZRANGE
你能够得到与指定用户有相同分数的用户名单。 全部这些操做都很是迅速。ZRANGEBYSCORE
能够简单快速地检索到给定年龄段的全部用户。有序集合或许是最高级的 Redis 数据类型,本系列教程后续会有 有序集合 专题会对经常使用命令以及场景进行介绍
Redis Hashes 是字符串字段和字符串值之间的映射,因此它们是完美的表示对象的数据类型。
一个拥有少许(100个左右)字段的 hash 须要 不多的空间来存储,因此你能够在一个小型的 Redis 实例中存储上百万的对象。
尽管 Hashes 主要用来表示对象,但它们也可以存储许多元素,因此你也能够用 Hashes 来完成许多其余的任务。
一个 hash 最多能够包含 2 ^ 32 - 1 个key-value键值对(超过40亿)。
本系列教程后续会有 哈希 专题会对经常使用命令以及场景进行介绍
Bit arrays (或者说 simply bitmaps): 经过特殊的命令,你能够将 String 值看成一系列 bits 处理:能够设置和清除单独的 bits,数出全部设为 1 的 bits 的数量,找到最前的被设为 1 或 0 的 bit,等等。
HyperLogLogs: 这是被用于估计一个 set 中元素数量的几率性的数据结构。
Redis 一样支持 Bitmaps 和 HyperLogLogs 数据类型,其实是基于字符串的基本类型的数据类型,但有本身的语义。
每种数据结构都有本身底层的内部编码实现,并且是多种实现,Redis 会在合适的场景选择合适的内部编码。这样设计的好处:
能够经过 object encoding
命令查询内部编码
Redis 是使用了 单线程架构
和 I/O多路复用模型
来实现高性能的内存数据库服务。
Redis 是单线程来处理命令的,因此命令到达 Redis 后并不会当即执行,而是进入队列以后逐个执行。对于差很少同时到达的命令执行的顺序是没法肯定的。
因为命令是逐个执行的,若是某个命令执行时间过长,则会形成其余命令的阻塞。因此 Redis 是面向快速执行场景的数据库。
业务名:对象名:id
的格式来声明键,键名应该尽量简短。