Redis学习日记-05:SORT命令

前言

在进行数据排序的时候很容易想到使用ZSET(有序集合)。然而有序集合常见的使用场景是大数据排序,如游戏玩家排行榜等,所以很少获取键中的全部数据。然而在Redis中对数据的排序除了用有序集合外还可以使用SORT命令。
SORT命令可以对列表、集合、有序集合类型的键进行排序。

命令&选项

以列表类型为例:

127.0.0.1:6379> lrange post 0 -1
1) "2"
2) "1"
3) "3"

SORT(默认根据元素由小到大):

127.0.0.1:6379> sort post
1) "1"
2) "2"
3) "3"

DESC(逆序):

127.0.0.1:6379> sort post desc
1) "3"
2) "2"
3) "1"

在SORT命令后面加上DESC选项即可将元素逆序排序

ALPHA(非数字元素排序):

127.0.0.1:6379> lrange strlist 0 -1
1) "d"
2) "B"
3) "C"
4) "b"
5) "A"

加上ALPHA选项(如果不加该选项会报错:(error) ERR One or more scores can't be converted into double)

127.0.0.1:6379> sort strlist alpha
1) "A"
2) "b"
3) "B"
4) "C"
5) "d"

该选项会按照字典顺序排序。

BY(参考键):

示例1

127.0.0.1:6379> hget post:1 count
"10"
127.0.0.1:6379> hget post:2 count
"15"
127.0.0.1:6379> hget post:3 count
"5"
127.0.0.1:6379> lrange post 0 -1
1) "2"
2) "1"
3) "3"
127.0.0.1:6379> sort post by post:*->count
1) "3"
2) "1"
3) "2"

实例2(某个参考键不存在的情况)

127.0.0.1:6379> lrange post 0 -1
1) "4"
2) "2"
3) "1"
4) "3"
127.0.0.1:6379> hget post:4 count
(nil)
127.0.0.1:6379> sort post by post:*->count
1) "4"
2) "3"
3) "1"
4) "2"
  • 该选项可以指定一个参考键(该参考键可以是字符串类型键或者散列类型键的某个字段)来进行排序,而不按照待排序键的元素大小排序。
    如上所示,BY选项后面的参数“post:->count”,表示按照“post:”开头的散列的count字段排序,过程中会用待排序键的元素替换“”,即先分别取到post:2、post:1、post:3的count字段的值,分别为15、10、5,并按该值由小到大排序(5,10,15)->(post:3,post:1,post:2),最后返回对应的待排序中的元素(3,1,2)。
  • 如果参考键是一个常量键或者不存在的键,则SORT的结果和LRANGE的结果相同,没有执行排序操作。常量键指的是不包含“*”,如“post:1->count”。
  • 如果参考键值相同,即如果上述post:1、post:2、post:3的count字段值相同,则SORT会按照待排序键元素本身来排序。
  • 如果某个元素对应的参考键不存在,则默认参考键的值为0。如上示例2,post:4这个散列并不存在,但是post中元素中加入了4,则排序会按照由小到大(0(post:4默认),5,10,15)->(post:4,post:3,post:1,post:2),最后返回对应的待排序中的元素(4,3,1,2)。

LIMIT(返回指定范围的结果):

127.0.0.1:6379> lrange post 0 -1
1) "4"
2) "2"
3) "1"
4) "3"
127.0.0.1:6379> sort post limit 1 3
1) "2"
2) "3"
3) "4"

LIMIT选项后面可以跟两个参数,一个是offset,代表从那个位置开始;另一个是count,代表取多少个元素。和Mysql的LIMIT语法很像。

GET(指定排序之后的返回数据):

示例1

127.0.0.1:6379> sort post by post:*->count get post:*->time
1) (nil)
2) "423"
3) "123"
4) "234"

实例2

127.0.0.1:6379> sort post by post:*->count get post:*->time get #
1) (nil)          ---post:*->time代表的值
2) "4"            ---元素本身的值
3) "423"
4) "3"
5) "123"
6) "1"
7) "234"
8) "2"
  • 实例1可以看到上面SORT命令后面跟了“get post:->time”,意思是该排序不返回待排序键元素本身,而是返回指定的以“post:”开头的散列类型键的time字段。
  • 你也可以使用“get #”来使其返回待排序键元素本身,如上示例2,依次输出GET选项对应的值。
  • SORT后面BY选项只能有一个,但是GET选项可以有多个。

STORE(将排序结果存入另一个键中)

针对上面GET命令示例2中的数据,再附加STORE选项:

127.0.0.1:6379> sort post by post:*->count get post:*->time get # store sort:result
(integer) 8
127.0.0.1:6379> type sort:result
list
127.0.0.1:6379> lrange sort:result 0 -1
1) ""
2) "4"
3) "423"
4) "3"
5) "123"
6) "1"
7) "234"
8) "2"

可以看到STORE选项后面跟了一个参数键sort:result,这个键可以是之前不存在的,命令执行后,会将排序返回的结果存放到该键中以列表的形式存在。

总结

  SORT是Redis最强大的命令之一,如果使用不当会造成性能瓶颈。SORT的时间复杂度为O(n+mlog(m)),其中n表示待排序元素的数量,m表示返回的元素数量。当n很大时,Redis在排序前建立一个长度为n的容器来存储待排序元素,因此同时进行大数据量的排序不管是在时间还是空间上消耗很多,从而降低性能。
  因此使用SORT命令时应该注意以下几点:

  1. 尽可能减少待排序键中的元素;
  2. 尽可能减少排序之后返回的数据,你可以使用上面提到的LIMIT选项来控制;
  3. 如果排序返回的结果较多,尽可能使用上面提到的STORE将排序结果缓存起来。
原文地址:https://www.cnblogs.com/xuxiaojian/p/9559989.html