🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
### 2.7.7 有序集合对象(zset) 有序集合对象的编码(encoding)可以是`ziplist`、 `skipist` 当有序集合对象同时满足以下两个条件时,使用ziplist编码,否则使用skiplist编码: - 所有元素长度小于64字节(可以通过`zset-max-ziplist-value`设置) - 元素数量小于128个(可以通过`zset-max-ziplist-entries`设置) ---- skiplist编码的对象使用zset作为底层数据结构: ```c typedef struct zset { zskiplist *zsl; dict *dict; }; ``` - zsl中按分值c从小到大排列了所有元素,可以对集合进行范围操作:ZRANK、ZRANGE等 - dict为所有元素创建了一个从成员到分值的映射,程序可以用O(1)的复杂度根据成员查找分值等,如ZSCORE - 通过指针共享相同元素 ---- ```c redis> ZADD price 8.5 apple 5.0 banana 6.0 cherry (integer) 3 ``` 如果price键使用ziplist编码,则其值对象如下所示: ``` redisObject type: REDIS_ZSET encoding: REDIS_ENCODING_ZIPLIST ptr -> ziplist: { zlbytes, zltail, zllen,"banana", 5.0, "cherry", 6.0, "apple", 8.5, zlend } ... ``` 如果price键使用skiplist编码,则其值对象如下所示: ``` redisObject type: REDIS_ZSET encoding: REDIS_ENCODING_SKIPLIST ptr -> zset: { dict: { dict, ..., h[0]: { dictht, ..., table: { (stringObject:"banana") -> 5.0 (stringObject:"apple") -> 8.5 (stringObject:"cherry") -> 6.0 }, ... },... }, zsl: { (header: ...), (tail: ...), (level: 5), (length: 3) } } ... ``` ---- 有序集合命令的实现: 命令 | ziplist的实现 | skiplist的实现 ---- | ---- | ---- ZAdd | 调用ziplistInsert函数,将成员和分值作为两个结点分别插入到压缩列表 | 先调用zslInsert函数插入跳跃表,再调用dictAdd函数插入到字典 ZCard | 调用ziplistLeng函数,将结果除以2后返回 | 返回跳跃表的length属性 ZCount | 遍历压缩列表,统计分值在给定范围内的结点数量 | 遍历跳跃表,统计分值在给定范围内的结点数量 ZRange | 从表头到表尾遍历压缩列表,返回给定索引范围内的所有元素 | 从表头到表尾遍历跳跃表,返回给定索引范围内的所有元素 ZRevRange | 从表尾到表头遍历压缩列表,返回给定索引范围内的所有元素 | 从表尾到表头遍历跳跃表,返回给定索引范围内的所有元素 ZRank | 从表头到表尾遍历压缩列表,查找指定元素,返回途径结点数,即排位 | 从表头到表尾遍历跳跃表,查找指定元素,返回途径结点数,即排位 ZRevRank | 从表尾到表头遍历压缩列表,查找指定元素,返回途径结点数,即排位 | 从表尾到表头遍历跳跃表,查找指定元素,返回途径结点数,即排位 ZRem | 遍历压缩列表,删除所有包含给定成员的结点,及其下一个值结点 | 遍历跳跃表,删除所有包含了给定成员的跳跃表结点,并在字典中解除被删除元素的成员和值的关联 ZScore | 遍历压缩列表,查找指定成员结点,取出其下一个结点即值结点 | 直接在字典中取出给定成员所对应的值