Redis研究(十七)—SORT排序,redis研究sort排序

來源:互聯網
上載者:User

Redis研究(十七)—SORT排序,redis研究sort排序

一、有序集合的集合操作

       集合類型提供了強大的集合操作命令,但是如果需要排序就要用到有序集合類型。Redis的作者在設計Redis的命令時考慮到了不同資料類型的使用情境,對於不常用到的或者在不損失過多效能的前提下可以使用現有命令來實現的功能,Redis就不會單獨提供命令來實現。這一原則使得Redis在擁有強大功能的同時保持著相對精簡的命令。

       有序集合常見的使用情境是大資料排序,如遊戲的玩家熱門排行榜,所以很少會需要獲得鍵中的全部資料。同樣Redis認為開發人員在做完交集、並集運算後不需要直接獲得全部結果,而是會希望將結果存入新的鍵中以便後續處理。這解釋了為什麼有序集合只有ZINTERSTORE和ZUNIONSTORE命令而沒有ZINTER和ZUNION命令。

       當然實際中需要直接獲得集合運算結果的情況,除了等待Redis加入相關命令,我們還可以使用MULTI , ZINTERSTORE, ZRANGE, DEL 和EXEC 這5個命令自己實現ZINTER:

MULTIZINTERSTORE tempKey...ZRANGE tempKey...DEL tempKey...EXEC

二、sort命令

       除了使用有序集合外,我們還可以藉助Redis提供的SORT。SORT命令可以對清單類型、集合類型和有序集合類型鍵進行排序,並且可以完成與關聯式資料庫中的串連查詢相類似的任務。

      比如標有“ruby”標籤的文章的ID分別是:“2”,“6”,“12”,“26”。由於在集合類型中所有元素是無序的,所以使用SMEMBERS命令並不能獲得有序的結果。為了能夠讓標籤頁面下的文章也能按照發布的時間順序排列(如果不考慮發布後再修改文章發布時間,就是按照文章ID的順序排列),可以藉助SORT命令實現,方法如下所示:

redis>SORT tag:ruby:posts1) "2"2) "6"3) "12"4) "26"

    除了集合類型,SORT命令還可以對清單類型和有序集合類型進行排序:


在對有序集合類型排序時會忽略元素的分數,只對元素自身的值進行排序。例如:


除了可以排列數字外,SORT命令還可以通過ALPHA參數實現按照字典順序排列非數字元素



SORT命令的 DESC參數可以實現將元素按照從大到小的順序排列:

redis>SORT tag:ruby:posts DESC1) "26"2) "12"3) "6"4) "2"

SORT命令還支援LIMIT參數來返回指定範圍的結果。用法和SQL 陳述式一樣,LIMIT offset  count,表示跳過前offset個元素並擷取之後的count個元素。
SORT命令的參數可以組合使用:

redis>SORT tag:ruby:posts DESC LIMIT 1 21) "12"2) "6"

三、BY參數

       BY 參數的文法為“BY參考鍵”。其中參考鍵可以是字串類型鍵或者是散列類型鍵的某個欄位(表示為鍵名—>欄位名)。如果提供了BY參數,SORT命令將不再依據元素自身的值進行排序,而是對每個元素使用元素的值替換參考鍵中的第一個“*”並擷取其值,然後依據該值對元素排序。


當參考鍵名不包含“*”時(即常量鍵名,與元素值無關),SORT命令將不會執行排序操作,因為Redis認為這種情況是沒有意義的(因為所有要比較的值都一樣)。例如:


例子中anytext是常量鍵名(甚至anytext鍵可以不存在),此時SORT的結果與LRANGE的結果相同,沒有執行排序操作。在不需要排序但需要藉助SORT命令獲得與元素相關聯的資料時,常量鍵名是很有用的。


如果幾個元素的參考鍵值相同,則SORT命令會再比較元素本身的值來決定元素的順序。

4和1的值都是50,會比較4和1本身的大小決定排序。


當某個元素的參考鍵不存在時,會預設參考鍵的值為0:

5的預設值為0,而3的為-10。


      參考鍵雖然支援散列類型,但是“*”只能在“->”符號前面( 即鍵名部分)才有用,在“->”後( 即欄位名部分) 會被當成欄位名本身而不會作為預留位置被元素的值替換,即常量鍵名。但是實際運行時會發現一個有趣的結果:

      上面提到了當參考鍵名是常量鍵名時SORT命令將不會執行排序操作,然而上例中確進行了排序,而且只是對元素本身進行排序。這是因為Redis判斷參考鍵名是不是常量鍵名的方式是判斷參考鍵名中是否包含“*”,而somekey->somefield :*中包含“*”所以不是常量鍵名。所以在排序的時候Redis對每個元素都會讀取鍵somekey中的somefield :*欄位( “*”不會被替換),本來無值,所以Redis會按照元素本身的大小排列。


四、GET參數

      GET參數不影響排序,它的作用是使SORT命令的返回結果不再是元素自身的值,而是GET參數中指定的鍵值。GET參數的規則和BY參數一樣,GET參數也支援字串類型和散列類型的鍵,並使用“*”作為預留位置。

       排序後直接返回對應的文章標題

redis>SORT tag:ruby:posts BY post:*->time DESC GET post:*->title

      在一個SORT命令中可以有多個GET參數(而BY參數只能有一個),

redis>SORT tag:ruby:posts BY post:*->time DESC GET post:*->title GET post:*->time
      有N個GET參數,每個元素返回的結果就有N行。

      GET #返回元素本身的值。


五、STORE參數

      預設情況下SORT會直接返回排序結果,如果希望儲存排序結果,可以使用STORE參數。如希望把結果儲存到sort.result鍵中:

redis>SORT tag:ruby:posts BY post:*->time DESC GET post:*->title GET post:*->time GET # STORE sort.result

儲存後的鍵的類型為清單類型,如果鍵已經存在則會覆蓋它。加上STORE參數後SORT命令的返回值為結果的個數。


六、效能最佳化

       SORT是Redis中最強大最複雜的命令之一,如果使用不好很容易成為效能瓶頸。SORT命令的時間複雜度是O(n+mlogm ),其中n 表示要排序的列表(集合或有序集合)中的元素個數,m表示要返回的元素個數。當n 較大的時候SORT命令的效能相對較低,並且Redis在排序前會建立一個長度為n(有一個例外是當鍵類型為有序集合且參考鍵為常量鍵名時容器大小為m 而不是n)的容器來儲存待排序的元素,雖然是一個臨時的過程,但如果同時進行較多的大資料量排序操作則會嚴重影響效能。


      所以開發中使用SORT命令時需要注意以下幾點。
(1)儘可能減少待排序鍵中元素的數量(使n 儘可能小)。
(2)使用LIMIT參數只擷取需要的資料(使m 儘可能小)。
(3)如果要排序的資料數量較大,儘可能使用STORE參數將結果緩衝。


相關文章

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.