同整數集合同樣壓縮列表也不是基礎數據結構,而是 Redis 本身設計的一種數據存儲結構。它有點兒相似數組,經過一片連續的內存空間,來存儲數據。不過,它跟數組不一樣的一點是,它容許存儲的數據大小不一樣。html
聽到「壓縮」兩個字,直觀的反應就是節省內存。之因此說這種存儲結構節省內存,是相較於數組的存儲思路而言的。咱們知道,數組要求每一個元素的大小相同,若是咱們要存儲不一樣長度的字符串,那咱們就須要用最大長度的字符串大小做爲元素的大小(假設是20個字節)。存儲小於 20 個字節長度的字符串的時候,便會浪費部分存儲空間。redis
數組的優點佔用一片連續的空間能夠很好的利用CPU緩存訪問數據。若是咱們想要保留這種優點,又想節省存儲空間咱們能夠對數組進行壓縮。數組
可是這樣有一個問題,咱們在遍歷它的時候因爲不知道每一個元素的大小是多少,所以也就沒法計算出下一個節點的具體位置。這個時候咱們能夠給每一個節點增長一個lenght的屬性。緩存
如此。咱們在遍歷節點的以後就知道每一個節點的長度(佔用內存的大小),就能夠很容易計算出下一個節點再內存中的位置。這種結構就像一個簡單的壓縮列表了。數據結構
壓縮列表(zip1ist)是列表和哈希的底層實現之一。運維
當一個列表只包含少許列表項,而且每一個列表項要麼就是小整數值,要麼就是長度比較短的字符串,那麼Redis就會使用壓縮列表來作列表的底層實現。編碼
當一個哈希只包含少許鍵值對,比且每一個鍵值對的鍵和值要麼就是小整數值,要麼就是長度比較短的字符串,那麼Redis就會使用壓縮列表來作哈希的底層實現。設計
壓縮列表是Redis爲了節約內存而開發的,是由一系列特殊編碼的連續內存塊組成的順序型(sequential)數據結枃。一個壓縮列表能夠包含任意多個節點(entry),每一個節點能夠保存一個字節數組或者一個整數值,以下圖。指針
示例:htm
如上圖,展現了一個總長爲80字節,包含3個節點的壓縮列表。若是咱們有一個指向壓縮列表起始地址的指針p,那麼表爲節點的地址就是P+60。
每一個壓縮列表節點能夠保存一個字節數組或者一個整數值。其中,字節數組能夠是如下三種長度中的一種。
整數值能夠是如下6種長度中的一種
節點的 previous_entry_length屬性以字節爲單位,記錄了壓縮列表中前一個節點的長度。 previous_entry_length屬性的長度能夠是1字節或者5字節。
節點的encoding屬性記錄了節點的content屬性所保存數據的類型以及長度。
節點的content屬性負責保存節點的值,節點值能夠是一個字節數組或者整數,值的類型和長度由節點的encoding屬性決定。
操做 | 時間複雜度 |
---|---|
建立一個新的壓縮列表 | O(1) |
建立一個包含給定值的新節點,並將這個新節點添加到壓縮列表的表頭或者表尾 | 平均O(N),最壞O(N^2)(可能發生連鎖更新) |
將包含給定值的新節點插人到給定節點以後 | 平均O(N),最壞O(N^2)(可能發生連鎖更新) |
返回壓縮列表給定索引上的節點 | O(N) |
在壓縮列表中査找並返回包含了給定值的節點 | 由於節點的值多是一個字節數組,因此檢查節點值和給定值是否相同的複雜度爲O(N),而查找整個列表的複雜度則爲(N^2) |
返回給定節點的下一個節點 | O(1) |
返回給定節點的前一個節點 | O(1) |
獲取給定節點所保存的值 | O(1) |
從壓縮列表中刪除給定的節點 | 平均O(N),最壞O(N^2)(可能發生連鎖更新) |
刪除壓縮列表在給定索引上的連續多個 | 平均O(N),最壞O(N^2)(可能發生連鎖更新) |
返回壓縮列表目前佔用的內存字節數 | O(1) |
返回壓縮列表目前包含的節點數量 | 點數量小於65535時爲O(1),大於65535時爲O(N) |
壓縮列表是Redis爲節約內存本身設計的一種順序型數據結構。
添加新節點到壓縮列表,或者從壓縮列表中刪除節點,可能會引起連鎖更新操做,但這種操做出現的概率並不高。
《Redis設計與實現》
《Redis開發與運維》
《Redis官方文檔》