# SORT
**SORT key [BY pattern] [LIMIT offset count] [GET pattern [GET pattern ...]] [ASC | DESC] [ALPHA] [STORE destination]**
返回或保存給定列表、集合、有序集合 `key` 中經過排序的元素。
排序默認以數字作為對象,值被解釋為雙精度浮點數,然后進行比較。
## 一般 SORT 用法
最簡單的 [SORT](#sort) 使用方法是 `SORT key` 和 `SORT key DESC` :
* `SORT key` 返回鍵值從小到大排序的結果。
* `SORT key DESC` 返回鍵值從大到小排序的結果。
假設 `today_cost` 列表保存了今日的開銷金額, 那么可以用 [SORT](#sort) 命令對它進行排序:
```
# 開銷金額列表
redis> LPUSH today_cost 30 1.5 10 8
(integer) 4
# 排序
redis> SORT today_cost
1) "1.5"
2) "8"
3) "10"
4) "30"
# 逆序排序
redis 127.0.0.1:6379> SORT today_cost DESC
1) "30"
2) "10"
3) "8"
4) "1.5"
```
## 使用 ALPHA 修飾符對字符串進行排序
因為 [SORT](#sort) 命令默認排序對象為數字, 當需要對字符串進行排序時, 需要顯式地在 [SORT](#sort) 命令之后添加 `ALPHA` 修飾符:
```
# 網址
redis> LPUSH website "www.reddit.com"
(integer) 1
redis> LPUSH website "www.slashdot.com"
(integer) 2
redis> LPUSH website "www.infoq.com"
(integer) 3
# 默認(按數字)排序
redis> SORT website
1) "www.infoq.com"
2) "www.slashdot.com"
3) "www.reddit.com"
# 按字符排序
redis> SORT website ALPHA
1) "www.infoq.com"
2) "www.reddit.com"
3) "www.slashdot.com"
```
如果系統正確地設置了 `LC_COLLATE` 環境變量的話,Redis能識別 `UTF-8` 編碼。
## 使用 LIMIT 修飾符限制返回結果
排序之后返回元素的數量可以通過 `LIMIT` 修飾符進行限制, 修飾符接受 `offset` 和 `count` 兩個參數:
* `offset` 指定要跳過的元素數量。
* `count` 指定跳過 `offset` 個指定的元素之后,要返回多少個對象。
以下例子返回排序結果的前 5 個對象( `offset` 為 `0` 表示沒有元素被跳過)。
```
# 添加測試數據,列表值為 1 指 10
redis 127.0.0.1:6379> RPUSH rank 1 3 5 7 9
(integer) 5
redis 127.0.0.1:6379> RPUSH rank 2 4 6 8 10
(integer) 10
# 返回列表中最小的 5 個值
redis 127.0.0.1:6379> SORT rank LIMIT 0 5
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
```
可以組合使用多個修飾符。以下例子返回從大到小排序的前 5 個對象。
```
redis 127.0.0.1:6379> SORT rank LIMIT 0 5 DESC
1) "10"
2) "9"
3) "8"
4) "7"
5) "6"
```
## 使用外部 key 進行排序
可以使用外部 `key` 的數據作為權重,代替默認的直接對比鍵值的方式來進行排序。
假設現在有用戶數據如下:
| uid | user_name_{uid} | user_level_{uid} |
| --- | --- | --- |
| 1 | admin | 9999 |
| 2 | jack | 10 |
| 3 | peter | 25 |
| 4 | mary | 70 |
以下代碼將數據輸入到 Redis 中:
```
# admin
redis 127.0.0.1:6379> LPUSH uid 1
(integer) 1
redis 127.0.0.1:6379> SET user_name_1 admin
OK
redis 127.0.0.1:6379> SET user_level_1 9999
OK
# jack
redis 127.0.0.1:6379> LPUSH uid 2
(integer) 2
redis 127.0.0.1:6379> SET user_name_2 jack
OK
redis 127.0.0.1:6379> SET user_level_2 10
OK
# peter
redis 127.0.0.1:6379> LPUSH uid 3
(integer) 3
redis 127.0.0.1:6379> SET user_name_3 peter
OK
redis 127.0.0.1:6379> SET user_level_3 25
OK
# mary
redis 127.0.0.1:6379> LPUSH uid 4
(integer) 4
redis 127.0.0.1:6379> SET user_name_4 mary
OK
redis 127.0.0.1:6379> SET user_level_4 70
OK
```
### BY 選項
默認情況下, `SORT uid` 直接按 `uid` 中的值排序:
```
redis 127.0.0.1:6379> SORT uid
1) "1" # admin
2) "2" # jack
3) "3" # peter
4) "4" # mary
```
通過使用 `BY` 選項,可以讓 `uid` 按其他鍵的元素來排序。
比如說, 以下代碼讓 `uid` 鍵按照 `user_level_{uid}` 的大小來排序:
```
redis 127.0.0.1:6379> SORT uid BY user_level_*
1) "2" # jack , level = 10
2) "3" # peter, level = 25
3) "4" # mary, level = 70
4) "1" # admin, level = 9999
```
`user_level_*` 是一個占位符, 它先取出 `uid` 中的值, 然后再用這個值來查找相應的鍵。
比如在對 `uid` 列表進行排序時, 程序就會先取出 `uid` 的值 `1` 、 `2` 、 `3` 、 `4` , 然后使用 `user_level_1` 、 `user_level_2` 、 `user_level_3` 和 `user_level_4` 的值作為排序 `uid` 的權重。
### GET 選項
使用 `GET` 選項, 可以根據排序的結果來取出相應的鍵值。
比如說, 以下代碼先排序 `uid` , 再取出鍵 `user_name_{uid}` 的值:
```
redis 127.0.0.1:6379> SORT uid GET user_name_*
1) "admin"
2) "jack"
3) "peter"
4) "mary"
```
### 組合使用 BY 和 GET
通過組合使用 `BY` 和 `GET` , 可以讓排序結果以更直觀的方式顯示出來。
比如說, 以下代碼先按 `user_level_{uid}` 來排序 `uid` 列表, 再取出相應的 `user_name_{uid}` 的值:
```
redis 127.0.0.1:6379> SORT uid BY user_level_* GET user_name_*
1) "jack" # level = 10
2) "peter" # level = 25
3) "mary" # level = 70
4) "admin" # level = 9999
```
現在的排序結果要比只使用 `SORT uid BY user_level_*` 要直觀得多。
### 獲取多個外部鍵
可以同時使用多個 `GET` 選項, 獲取多個外部鍵的值。
以下代碼就按 `uid` 分別獲取 `user_level_{uid}` 和 `user_name_{uid}` :
```
redis 127.0.0.1:6379> SORT uid GET user_level_* GET user_name_*
1) "9999" # level
2) "admin" # name
3) "10"
4) "jack"
5) "25"
6) "peter"
7) "70"
8) "mary"
```
`GET` 有一個額外的參數規則,那就是 —— 可以用 `#` 獲取被排序鍵的值。
以下代碼就將 `uid` 的值、及其相應的 `user_level_*` 和 `user_name_*` 都返回為結果:
```
redis 127.0.0.1:6379> SORT uid GET # GET user_level_* GET user_name_*
1) "1" # uid
2) "9999" # level
3) "admin" # name
4) "2"
5) "10"
6) "jack"
7) "3"
8) "25"
9) "peter"
10) "4"
11) "70"
12) "mary"
```
### 獲取外部鍵,但不進行排序
通過將一個不存在的鍵作為參數傳給 `BY` 選項, 可以讓 `SORT` 跳過排序操作, 直接返回結果:
```
redis 127.0.0.1:6379> SORT uid BY not-exists-key
1) "4"
2) "3"
3) "2"
4) "1"
```
這種用法在單獨使用時,沒什么實際用處。
不過,通過將這種用法和 `GET` 選項配合, 就可以在不排序的情況下, 獲取多個外部鍵, 相當于執行一個整合的獲取操作(類似于 SQL 數據庫的 `join` 關鍵字)。
以下代碼演示了,如何在不引起排序的情況下,使用 `SORT` 、 `BY` 和 `GET` 獲取多個外部鍵:
```
redis 127.0.0.1:6379> SORT uid BY not-exists-key GET # GET user_level_* GET user_name_*
1) "4" # id
2) "70" # level
3) "mary" # name
4) "3"
5) "25"
6) "peter"
7) "2"
8) "10"
9) "jack"
10) "1"
11) "9999"
12) "admin"
```
### 將哈希表作為 GET 或 BY 的參數
除了可以將字符串鍵之外, 哈希表也可以作為 `GET` 或 `BY` 選項的參數來使用。
比如說,對于前面給出的用戶信息表:
| uid | user_name_{uid} | user_level_{uid} |
| --- | --- | --- |
| 1 | admin | 9999 |
| 2 | jack | 10 |
| 3 | peter | 25 |
| 4 | mary | 70 |
我們可以不將用戶的名字和級別保存在 `user_name_{uid}` 和 `user_level_{uid}` 兩個字符串鍵中, 而是用一個帶有 `name` 域和 `level` 域的哈希表 `user_info_{uid}` 來保存用戶的名字和級別信息:
```
redis 127.0.0.1:6379> HMSET user_info_1 name admin level 9999
OK
redis 127.0.0.1:6379> HMSET user_info_2 name jack level 10
OK
redis 127.0.0.1:6379> HMSET user_info_3 name peter level 25
OK
redis 127.0.0.1:6379> HMSET user_info_4 name mary level 70
OK
```
之后, `BY` 和 `GET` 選項都可以用 `key->field` 的格式來獲取哈希表中的域的值, 其中 `key` 表示哈希表鍵, 而 `field` 則表示哈希表的域:
```
redis 127.0.0.1:6379> SORT uid BY user_info_*->level
1) "2"
2) "3"
3) "4"
4) "1"
redis 127.0.0.1:6379> SORT uid BY user_info_*->level GET user_info_*->name
1) "jack"
2) "peter"
3) "mary"
4) "admin"
```
## 保存排序結果
默認情況下, [SORT](#sort) 操作只是簡單地返回排序結果,并不進行任何保存操作。
通過給 `STORE` 選項指定一個 `key` 參數,可以將排序結果保存到給定的鍵上。
如果被指定的 `key` 已存在,那么原有的值將被排序結果覆蓋。
```
# 測試數據
redis 127.0.0.1:6379> RPUSH numbers 1 3 5 7 9
(integer) 5
redis 127.0.0.1:6379> RPUSH numbers 2 4 6 8 10
(integer) 10
redis 127.0.0.1:6379> LRANGE numbers 0 -1
1) "1"
2) "3"
3) "5"
4) "7"
5) "9"
6) "2"
7) "4"
8) "6"
9) "8"
10) "10"
redis 127.0.0.1:6379> SORT numbers STORE sorted-numbers
(integer) 10
# 排序后的結果
redis 127.0.0.1:6379> LRANGE sorted-numbers 0 -1
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"
7) "7"
8) "8"
9) "9"
10) "10"
```
可以通過將 [SORT](#sort) 命令的執行結果保存,并用 [_EXPIRE_](expire.html#expire) 為結果設置生存時間,以此來產生一個 [SORT](#sort) 操作的結果緩存。
這樣就可以避免對 [SORT](#sort) 操作的頻繁調用:只有當結果集過期時,才需要再調用一次 [SORT](#sort) 操作。
另外,為了正確實現這一用法,你可能需要加鎖以避免多個客戶端同時進行緩存重建(也就是多個客戶端,同一時間進行 [SORT](#sort) 操作,并保存為結果集),具體參見 [_SETNX_](../string/setnx.html#setnx) 命令。
**可用版本:**
>= 1.0.0
**時間復雜度:**
O(N+M*log(M)), `N` 為要排序的列表或集合內的元素數量, `M` 為要返回的元素數量。如果只是使用 [SORT](#sort) 命令的 `GET` 選項獲取數據而沒有進行排序,時間復雜度 O(N)。
**返回值:**
沒有使用 `STORE` 參數,返回列表形式的排序結果。使用 `STORE` 參數,返回排序結果的元素數量。<split>
# TTL
**TTL key**
以秒為單位,返回給定 `key` 的剩余生存時間(TTL, time to live)。
**可用版本:**
>= 1.0.0
**時間復雜度:**
O(1)
**返回值:**
當 `key` 不存在時,返回 `-2` 。當 `key` 存在但沒有設置剩余生存時間時,返回 `-1` 。否則,以秒為單位,返回 `key` 的剩余生存時間。
Note
在 Redis 2.8 以前,當 `key` 不存在,或者 `key` 沒有設置剩余生存時間時,命令都返回 `-1` 。
```
# 不存在的 key
redis> FLUSHDB
OK
redis> TTL key
(integer) -2
# key 存在,但沒有設置剩余生存時間
redis> SET key value
OK
redis> TTL key
(integer) -1
# 有剩余生存時間的 key
redis> EXPIRE key 10086
(integer) 1
redis> TTL key
(integer) 10084
```
- Redis 教程
- Redis 簡介
- Redis 安裝
- Redis 配置
- Redis 數據類型
- Redis 命令
- Redis 數據備份與恢復
- Redis 安全
- Redis 性能測試
- Redis 客戶端連接
- Redis 管道技術
- Redis 分區
- Java 使用 Redis
- Java 使用 Redis
- PHP 使用 Redis
- PHP 使用 Redis
- Redis 命令參考
- Key(鍵)
- DEL
- DUMP
- EXISTS
- EXPIRE
- EXPIREAT
- KEYS
- MIGRATE
- MOVE
- OBJECT
- PERSIST
- PEXPIRE
- PEXPIREAT
- PTTL
- RANDOMKEY
- RENAME
- RENAMENX
- RESTORE
- SORT
- TYPE
- SCAN
- String(字符串)
- APPEND
- BITCOUNT
- BITOP
- DECR
- DECRBY
- GET
- GETBIT
- GETRANGE
- GETSET
- INCR
- INCRBY
- INCRBYFLOAT
- MGET
- MSET
- MSETNX
- PSETEX
- SET
- SETBIT
- SETEX
- SETNX
- SETRANGE
- STRLEN
- Hash(哈希表)
- HDEL
- HEXISTS
- HGET
- HGETALL
- HINCRBY
- HINCRBYFLOAT
- HKEYS
- HLEN
- HMGET
- HMSET
- HSET
- HSETNX
- HVALS
- HSCAN
- List(列表)
- BLPOP
- BRPOP
- BRPOPLPUSH
- LINDEX
- LINSERT
- LLEN
- LPOP
- LPUSH
- LRANGE
- LREM
- LSET
- LTRIM
- RPOP
- RPOPLPUSH
- RPUSH
- RPUSHX
- Set(集合)
- SADD
- SCARD
- SDIFF
- SDIFFSTORE
- SINTER
- SINTER
- SINTERSTORE
- SISMEMBER
- SMEMBERS
- SMOVE
- SPOP
- SRANDMEMBER
- SREM
- SUNION
- SUNIONSTORE
- SSCAN
- SortedSet(有序集合)
- ZADD
- ZCARD
- ZCOUNT
- ZINCRBY
- ZRANGE
- ZRANGEBYSCORE
- ZRANK
- ZREM
- ZREMRANGEBYRANK
- ZREMRANGEBYSCORE
- ZREVRANGE
- ZREVRANGEBYSCORE
- ZREVRANK
- ZSCORE
- ZUNIONSTORE
- ZINTERSTORE
- ZSCAN
- Pub/Sub(發布/訂閱)
- PSUBSCRIBE
- PUBLISH
- PUBSUB
- PUNSUBSCRIBE
- SUBSCRIBE
- UNSUBSCRIBE
- Transaction(事務)
- DISCARD
- EXEC
- MULTI
- UNWATCH
- WATCH
- Script(腳本)
- EVAL
- EVALSHA
- SCRIPT EXISTS
- SCRIPT FLUSH
- SCRIPT KILL
- SCRIPT LOAD
- Connection(連接)
- AUTH
- ECHO
- PING
- QUIT
- SELECT
- Server(服務器)
- BGREWRITEAOF
- BGSAVE
- CLIENT GETNAME
- CLIENT KILL
- CLIENT LIST
- CLIENT SETNAME
- CONFIG GET
- CONFIG RESETSTAT
- CONFIG REWRITE
- CONFIG SET
- DBSIZE
- DEBUG OBJECT
- DEBUG SEGFAULT
- FLUSHALL
- FLUSHDB
- INFO
- LASTSAVE
- MONITOR
- PSYNC
- SAVE
- SHUTDOWN
- SLAVEOF
- SLOWLOG
- SYNC
- TIME
- 免責聲明