#### Redis系列(六)-SortedSets設計技巧
閱讀目錄:
[TOC]
#### 介紹
Redis Sorted Sets是類似Redis Sets數據結構,不允許重復項的String集合。不同的是Sorted Sets中的每個成員都分配了一個分數值(score),它用于在Sorted Sets中進行成員排序,從最小值到最大值。Sorted Sets中所有的成員都是唯一的,其分數(score)是可以重復的,即是說一個分數可能會對應多個值。
用Sorted Sets可以非常快的進行添加、刪除、或更新成員,其復雜度是`O(m*log(n))`,m是添加或查詢的成員數量。因為成員是按照順序添加的,所以可以非常快的通過score或者索引進行范圍查詢。訪問Sorted Sets中間的元素也是非常快的,因此可以用sort sets作為一個不重復的小型有序列表。 通過Sorted Sets可以快速操作任何你想做的事情:排序的成員,判斷成員是否在集合中,快速訪問集合中間的成員。
如果多次添加相同的值到Sorted Sets上,redis會以最后一次的值分數為準。
總的來說,在其他數據庫比較難完成的任務,用Sorted Sets可以更快更優性能的完成。
更多Sorted Sets的用法可以查看官方文檔。
#### Score占位
Sorted Sets中的Score是個64位整數類型,其范圍在-9007199254740992到9007199254740992之間,這是一個非常有用的關鍵點。
我們通常可以用它進行簡單的范圍查詢,比如把年齡當分數,通過ZRANGEBYSCORE查詢某個年齡段的所有用戶。
查詢18-35年齡的用戶:
~~~
ZRANGEBYSCORE user 18 35
~~~
如果有更復雜的需求,比如通過日期,用戶類型等來查詢,就比較困難了。 如果用其他數據結構的話,想查詢多條時就要多次往返操作,有性能上的損耗。 這里可以用Score整數類型的長度特性,來存儲查詢的條件信息。
比如有些數據需要通過日期范圍查詢,這是個很常見的場景。
使用Sorted Sets當存儲的數據結構,添加key時把日期進行簡單的轉碼。
一年有365天,在score中預留三位來存儲天份,通過DayOfYear計算出一年第多少天:
~~~
var time1=DateTime.Now.DayOfYear
~~~
因為第100天前的數據不滿三位,需要進行用0補全,寫個方法:
~~~
string AutoCompletion(int length, int num)
{
string str = num.ToString();
if (str.Length > length)
throw new Exception("max length");
var real = length - str.Length;
var sb = new StringBuilder(length);
for (int j = 0; j < real; j++)
{
sb.Append((char) 48);
}
sb.Append(str);
return sb.ToString();
}
~~~
因為數據的日期可能跨年,在天位前預留2位,存儲年份。現在長度是5位,如15200表示的是15年19號(第200天)。
通過年份+天數計算出當前數據項score的值。
~~~
var score= long.Parse(dateTime.Year.ToString().Substring(2, 2) + AutoCompletion(3, dateTime.DayOfYear));
~~~
把實際值和分數值存儲到redis里面:
~~~
ZADD test score value
~~~
查詢時把需要查詢的日期范圍轉換到分數,這里查詢前10天的數據:
~~~
int time1 = DateTime.Now.DayOfYear;
var score1 = AutoCompletion(time1, 2) + AutoCompletion(DateTime.Now.DayOfYear, 3);
int time2 = DateTime.Now.DayOfYear;
var score2 = AutoCompletion(time1, 2) + AutoCompletion(DateTime.Now.AddDays(-10).ToLocalTime().DayOfYear, 3);
~~~
在redis中查詢:
~~~
ZRANGEBYSCORE user score1 score2
~~~
查詢當天(分數)下的信息:
~~~
ZRANGEBYSCORE user score2 score2
~~~
#### 更多位信息
r64位整數類型有16個位置,意味著還可以存儲更多維度信息。這里以日期為主,在增加個類型維度,日期位置左移4位,預留4位來存儲類型維度。
如152003456,其3456四位是存儲類型的,可以根據類型種類的多少可以增加位或減少位占用。
如果單純以日期來查詢時,類型不用傳,后面4位在查詢時補千位最小值和最大值即可。
查詢前10天的數據:
~~~
ZRANGEBYSCORE user 151900000 152009999
~~~
查詢15年19號3578類型的數據:
~~~
ZRANGEBYSCORE user 152003578 152003578
~~~
查詢15年19號1000-4000類型的數據:
~~~
ZRANGEBYSCORE user 152001000 152004000
~~~
關于類型往往不是簡單的數據類型那么簡單,可以做個簡單的mapping表。
~~~
abcd 1000
dcda 1001
~~~
以此類推...
在添加時或查詢時注意轉換。
#### 總結
需要注意的是score是整數類型按從小到大排序存儲的,按照上面的設計是不能在指定類型的情況下,進行日期范圍查找的,因為我們定義日期作為主維度。
通常在數據庫中有很多層級關系的表,比如大分類、子分類、小分類等一級一級遞減。 使用Sorted Sets我們可以模擬這種關系去設計Score值,主維度->次維度->低維度,這樣就可以更快的進行范圍分類信息的查詢,有個前提是64位整數的位置夠用。
如果沒有類似的需求,可以使用時間戳作為值的分數值,這樣就不需要額外的轉換了。
簡單分享了Sorted Sets存儲設計的經驗,希望對大家有所幫助。
- 目錄
- 安裝擴展
- 在 Windows 上安裝 PHP 擴展
- 測試Redis擴展函數
- 教程
- 簡介
- Redis 安裝
- Redis 配置
- 運行
- 測試
- 書籍
- 《Redis開發與運維》
- 《Redis入門指南》
- 《Redis實戰》
- 《當 Redis 遇上 ThinkPHP5》
- 參考站點
- 下載
- 命令參考
- 管理工具
- 視頻
- 云數據庫 Redis 版使用教程
- Redis 深入之道
- Redis高可用教程
- Redis入門
- NoSQL概述
- Redis概述
- Redis安裝
- Jedis入門
- PHP命令
- PHP中利用Redis管道加快執行
- Hash操作
- Set操作
- Gearman
- MySQL - Redis配合使用方案
- 應用場景
- 緩存應用
- Redis實現簡單的條件查詢功能
- 獲取網站中點擊量最高的前n篇文章
- 顯示最新的項目列表
- 排行榜相關
- 設計技巧
- SortedSets
- List列表
- 消息隊列
- 最新文章
- Set集合
- 共同好友
- 獨立 IP
- Linux教程
- 常用命令
- 哈希命令
- 字符串
- 集合
- 有序集合
- Redis 有序集合命令
- 有序集合命令(中)
- 發布訂閱
- 用例
- 列表
- Lindex
- Ltrim
- Rpush
- Lset
- Llen
- Lpush
- 信息
- info memory
- 安裝
- 數據類型
- Redis管道(pipeline)
- Memory Command
- 阿里云Redis
- 架構
- 4.0版本
- Redis 4.0 新功能介紹
- Redis Desktop Manager
- 創建hash列表數據
- Lua: 給 Redis 用戶的入門指導
- Lua入門
- 樂觀鎖介紹
- 悲觀鎖介紹
- 臟數據
- Redis核心概念
- Redis事務
- Lua
- 在Redis中使用lua腳本
- php-redis
- mysql緩存服務器
- redis setnx 實現分布式鎖和單機鎖
- 為什么分布式一定要有Redis?