集合类型提供了强大的集合操作命令,但是如果需要排序就要用到有序集合类型。Redis的作者在设计Redis的命令时考虑到了不同数据类型的使用场景,对于不常用到的或者在不损失过多性能的前提下可以使用现有命令来实现的功能,Redis就不会单独提供命令来实现。这一原则使得Redis在拥有强大功能的同时保持着相对精简的命令。
有序集合常见的使用场景是大数据排序,如游戏的玩家排行榜等等,所以很少会需要获得键中的全部数据。同样Redis认为开发者在做完交集、并集运算后不需要直接获得全部结果,而是会希望将结果存入新的键中以便后续处理
。
点击查看:有序集合的相关命令
除了使用有序集合外,我们还可以借助 Redis提供的 SORT命令来实现集合的排序。
SORT命令可以对列表类型、集合类型和有序集合类型键进行排序
,并且可以完成与关系型数据库的连接查询相类似的任务。
由于在集合类型中所有元素是无序的,所以使用 smsmbers命令并不能获得有序的结果,因此可以借助SORT命令实现排序操作:
# 升序(默认)
sort key
# 降序
sort key desc
# 升序(默认)
sort key
# 降序
sort key desc
在对有序集合类型排列时会忽略元素的分数,只针对元素自身的值进行排序。
# 升序(默认)
sort key
# 降序
sort key desc
除了可以排列数字外,SORT命令还可以通过ALPHA参数实现按照字典顺序排列非数字元素。
sort key ALPHA
小贴士:
- SORT排序默认是按照升序排列的,通过desc关键字实现降序排列;
- 可以使用 LIMIT关键字实现分页查询功能。
很多情况下,列表(或集合、有序集合)中存储的元素值代表的是对象的ID,单纯对这些ID自身排序有时意义并不大,更多的时候我们希望根据ID对应的对象的某个属性进行排序
。
有这样一个场景:
以博客文章为例,time字段存储文章的发布时间,id字段存储文章的id,要求按照文章的发布时间对文章id排序显示,这时就需要使用参数BY来辅助使用了。
BY参数的语法为BY参考键。其中参考键可以是字符串类型键或者是散列类型键的某个字段(表示为键名->字段名)。如果提供了BY参数,SORT命令将不再依据元素自身的值进行排序,而是对每个元素使用元素的值替换参考键中的第一个"*"并获取其值,然后依据该值对元素排序。
参考键是散列类型的数据,根据文章发布时间排序对其id进行排序。
# 升序(默认)
sort sortbyitem by 键名->字段名
# 降序
sort sortbyitem by 键名->字段名 desc
# 升序(默认)
sort sortbylist by item
# 降序
sort sortbylist by item desc
当参考键名不包含" * "时(即常量键名,与元素值无关),SORT命令将不会执行排序操作,因为Redis认为这种情况是没有意义的(因为所有要比较的值都一样)。
这里的 anytext是常量键名(甚至anytext键可以不存在),此时 SORT的结果与 LRANGE的结果相同,没有执行排序操作。在不需要排序但是需要借助 SORT命令获得与元素相关联的数据时,常量键名是很有用的。
如果几个元素的参考键值相同,则SORT命令会再比较元素本身的值来决定元素的顺序。但是当某个元素的参考键不存在时,会默认参考键的值为0。
参考键值虽然支持散列类型,但是" * "只能在" -> "符号前面(即键名部分)才有用,在" -> "后(即字段部分)会被当成字段名本身而不会作为占位符被元素的值替换,即常量键名。
Redis判断参考键名是不是常量键名的方式使判断参考键名中是否包含" * “,而 itemscore:* 中包含” * “,所以不是常量键名。即在排序的时候Redis对每个元素都会读取键 itemscore中的 itemscore:* 字段,这里的” * "是不会被替换的,无论能否获得其值,每个元素的参考键值是相同的,所以Redis会按照元素本身的大小排列。
有如下场景:
现在已经实现了按照文章的发布顺序获取一个标签下的文章ID列表了,接下来就是对每个ID都是用HGET命令获取文章的标题以显示在博客列表页中。
GET参数不影响排序,它的作用是使用SORT命令的返回结果不再是元素自身的值,而是GET参数中指定的键值。
GET参数的规则和BY参数一样,GET参数也支持字符串类型和散列类型的键,并使用" * "作为占位符。
# 获取N个
sort sortbyitem by 键名->字段名 desc get 键名->字段名 get 键名->字段名...
# 返回元素本身的值
sort sortbyitem by 键名->字段名 desc get 键名->字段名 get 键名->字段名 get #
一个SORT命令中可以有多个GET参数(而BY参数只能有一个)。
有N个GET参数,每个元素返回的结果就有N行,使用GET #可以返回元素本身的值。
默认情况下SORT会直接返回排序结果,如果希望保存排序结果,可以使用STORE参数。
sort sortbyitem by 键名->字段名 desc get 键名->字段名 get 键名->字段名 get # store sort.result
保存后的键的类型为列表类型,如果键已经存在则会覆盖它。加上DTORE参数后SORT命令的返回值为结果的个数。
STORE参数常用来结合EXPIRE命令缓存排序结果。
SORT是Redis中最强大最复杂的命令之一,如果使用不好很容易成为性能瓶颈。SORT命令的时间复杂度是O(n+mlog(m)),其中n表示要排序的列表(集合或有序集合)中的元素个 数,m表示要返回的元素个数。当n较大的时候SORT命令的性能相对较低,并且Redis在排序前会建立一个长度为 n 的容器来存储待排序的元素,虽然是一个临时的过程,但如果同时进行较多的大数据量排序操作则会严重影响性能。
所以开发中使用SORT命令时需要注意以下几点: