生存時間
設置命令
expire key long:設置數據在long秒后過期。
pexpire key long:設置數據在long毫秒后過期。
ttl key:查詢數據剩余的生存時間。如果數據已過期被刪除,返回-2(和版本有關),如果數據沒有被設置過期時間,返回-1。
persist key:取消數據的生存時間,重新變成永久生存。
expireat key long:使用UNIX時間,設置數據存活到long時刻。long是從1980年8月1日開始到生存截止時間的秒數。
pexpireat key long:使用UNIX時間,設置數據存貨到long時刻,long是從1980年8月1日開始到生存截止時間的毫秒數。
注意事項
(1)數據過期並不是表示一定會被立即刪除
Redis不可能時時刻刻遍歷所有被設置了生存時間的key,來檢測數據是否已經到達過期時間,然后對它進行刪除。這會產生大量的性能消耗,同時也會影響數據的讀取操作。
在Redis中,采用了定期刪除和惰性刪除的策略來防止用戶獲取過期了的數據。
- 定期刪除:定期隨機獲取某些數據,檢測它們是否已經過期,對過期數據進行刪除。
- 惰性刪除:用戶查詢某個數據前,檢查它的生存時間是否已經過期,如果是,對它進行刪除。
(2)Set和GetSet命令會清除過期時間
執行了Set和GetSet命令對key重新賦值,會同時清除掉它的生存時間。要注意目前只有這兩個命令能清楚生存時間,其余的如hset、lpush等均不行。
刪除策略
Redis的最大內存和刪除策略都是在配置文件中進行配置。
配置參數
maxmemory:配置最大可用內存。
maxmemory-policy:配置達到最大內存后的刪除策略。
maxmemory-samples:指定刪除策略中隨機取數的個數。
注意事項
(1)刪除策略
volatile-lru:從設置了生存時間的數據中,找到使用最少的數據刪除(LRU算法是找出使用時間最久遠的數據)。
allkeys-lru:從所有數據中,找到使用最少的數據刪除。
volatile-random:從設置生存時間的數據中,隨機刪除一個數據。
allkeys-random:從所有數據中,隨機刪除一個數據。
volatile-ttl:刪除設置了生存時間中,ttl查詢出來的時間最少的數據。
noeviction:不刪除數據,返回錯誤。
(2)刪除策略並不會全表掃描
和數據過期的情形一樣,假如使用volatile-lru策略,按字面意思Redis需要遍歷所有的數據,找出他們最后一次的使用時間,然后比較誰最久沒有被使用,就刪除它。但是實際這樣操作會產生極為嚴重的性能消耗,降低Redis的讀寫性能。因此在刪除策略中,Redis也是采用了隨機數據的方式,每次隨機取某些數據,在這些數據中執行LRU算法,RANDOM算法,或者是找出TTL時間最少的數據,而不會掃描全部數據。至於每次取多少數據,通過參數maxmemory-samples配置。
排序
排序其實只有一個命令SORT,但是在這個命令后面可以配置許多不同的參數來滿足不同的情況需求。
詳細命令
SORT KEY [BY 參考鍵] [ALPHA] [DESC|ASC] [LIMIT OFFSET COUNT] [GET 參考鍵] [STORE KEY]
命令說明
sort key:最簡單的排序命令,可以使用在列表類型、集合類型和無序集合類型中,將數字類型的鍵值按照從小到大的順序排列,鍵值是字符串將返回錯誤。
下面的命令都是建立在sort key的基礎上的擴展。
- sort key alpha:新增可以對字符串的排序。
- sort key desc:排序順序變為從大到小。
- sort key limit offset count:常用在分頁上。排序后,按從左往右的順序從下標為offset的元素開始返回,一共返回count個元素。
- sort key store key1:將返回結果保存在key1上。
- sort key by 參考鍵:依照參考鍵內容進行排序,排序結果仍返回key的鍵值。參考鍵可以是字符串類型和散列類型,必須帶*,否則不會執行排序。
- sort key get 參考鍵:排序后返回參考鍵的鍵值,參考鍵可以是字符串類型和散列類型。
下面會進行相關的樣例說明
樣例1:創建一個列表類型list=[0 6 2 4 8 9 3 1],對它進行排序,排序結果[0 1 2 3 4 6 8 9]。
注意:這里只是對list的數據作有序返回,而並沒有改變list里面元素的順序。如果此時再通過lrange list 0 -1直接輸出list的內容,將仍然是[0 6 2 4 8 9 3 1]
樣例2:創建一個列表類型list=[b c e d a],先直接用sort對它排序,會返回一個錯誤,根據錯誤提示我們可以發現sort其實是將鍵值轉為雙精度浮點類型的數據來進行比較的。字符串類型需要添加參數alpha來進行標注,告訴redis這里是對字符串類型排序。
樣例3:使用樣例2的list,使用desc對它進行了倒序排序。
樣例4:使用樣例2的list,限制了返回值要從從下標為2的元素開始,連續取兩個元素返回(Redis中的下標從左往右是從0開始,從右往左是從-1開始)。
樣例5:在樣例4的基礎上,使用store命令,將返回結果保存在list2中,查詢list2的結果可以看到里面只有兩個元素c和d
樣例6:在樣例2的list上,我們這里又創建了三個字符串類型數據s:a=3,s:b=5,s:c=-2。然后使用by 參考鍵來指定list的排序方式。
在這里有幾個奇怪的地方:
- 返回的結果是字符串類型,但是我們沒有使用alpha參數。
- 在不使用desc的情況下,默認是按從小到大的順序排序,正常的應該是[a b c d e],但是實際返回的順序是[c d e a b]
由於我們在這里使用了'by 參考鍵',因此它排序實際是依據s:*的鍵值來進行,因為我們list的鍵值是[a b c d e],用它們替代by s:*的通配符,分別對應[s:a s:b s:c s:d s:e],由於s:d和s:e並不存在,因此會使用0來作為他們的鍵值,因此取出來的數據是[3 5 -2 0 0],這些都是數字類型,因此並不需要使用alpha參數,同時對他們按從小到大的順序排序[-2 0 0 3 5],分別對應[s:c s:d s:e s:a s:b],對應list的值就是[c d e a b],里面s:d和s:e都是0,當使用參考鍵的鍵值不能排序的時候,會再按照list里的鍵值進行排序,因此最終結果是[c d e a b]。
樣例7:在樣例6的基礎上,我們使用'get 參考鍵'來獲取數據,排序使用的是list的鍵值,因此排序結果是[a b c d e],然后匹配get后面的參考鍵s:*,可以匹配為[s:a s:b s:c s:d s:e],由於s:d和s:e不存在,因此返回nil。
注意事項
- by和get的參考鍵中沒有*時,不會進行排序。
- by和get的參考鍵鍵值相等時,會在按照key的鍵值排序。
- 如果key的鍵值匹配by的參考鍵組成的鍵不存在,則默認鍵值為0。
- 在by和get的參考鍵中,*只能使用在字符串類型和散列類型的鍵上,不能使用在散列類型的域上。
- 由上一條引發出來的問題,如果將*使用在散列類型的域上,由於Redis檢測參考鍵中有*,因此會進行排序,但是不會用key的鍵值替換*,因此只是按照key的鍵值進行的排序。
- get可以返回多個元素,以'get 參考鍵 get 參考鍵...'的形式排列,同時如果要返回*的內容,使用get #
排序時間復雜度
sort時間復雜度是O(n+mlogm),其中n是被排序數據的個數,m是返回結果的個數。
因此,如果要優化sort性能,只要考慮減小n和m的值即可。
- 盡可能減少待排序中元素的數量。
- 盡可能使用limit減少返回的元素數量。
- 盡可能得將返回結果使用store保存,而不是直接返回。