Redis数据类型 — Set

目录

Set内部实现

源码片段


Set 类型是一个无序并唯一的键值集合,它的存储顺序不会按照插入的先后顺序进行存储。一个集合最多可以存储 2^32-1 个元素。

Set 类型除了支持集合内的增删改查,同时还支持多个集合取交集、并集、差集
Set 的差集、并集和交集的计算复杂度较高,在数据量较大的情况下,如果直接执行这些计算,会导致 Redis 实例阻塞。可以选择一个从库完成聚合统计,或者把数据返回给客户端,由客户端来完成聚合统计。

Set 类型和 List 类型的区别如下:

  • List 可以存储重复元素,Set 只能存储非重复元素;
  • List 是按照元素的先后顺序存储元素的,而 Set 则是无序方式存储元素的。

Set内部实现

Set 类型的底层数据结构是由哈希表Dict或整数集合IntSet实现的:

  • 如果集合中的元素都是整数且元素个数小于 512 (默认值,set-maxintset-entries配置)个,Redis 会使用整数集合作为 Set 类型的底层数据结构,以节省空间;
  • 如果集合中的元素不满足上面条件,则 Redis 使用哈希表作为 Set 类型的底层数据结构,Dict中的key用来存储元素,value统一为null。

Redis数据类型 — Set_第1张图片

源码片段

Set存储数据片段

Redis数据类型 — Set_第2张图片

Intset转换成Dict存储片段 

int setTypeAdd(robj *subject, sds value) {
    long long llval;
    //已经是哈希编码,直接添加元素
    if (subject->encoding == OBJ_ENCODING_HT) {
        dict *ht = subject->ptr;
        dictEntry *de = dictAddRaw(ht,value,NULL);
        if (de) {
            dictSetKey(ht,de,sdsdup(value));
            dictSetVal(ht,de,NULL);
            return 1;
        }
    }
    //目前是IntSet 
	else if (subject->encoding == OBJ_ENCODING_INTSET) {
        //判断value是否是整数
        if (isSdsRepresentableAsLongLong(value,&llval) == C_OK) {
            uint8_t success = 0; //是整数,直接添加元素到set
            subject->ptr = intsetAdd(subject->ptr,llval,&success);
            if (success) {
                /* 当intset元素超出set_max_intset_entries,则转为哈希*/
                if (intsetLen(subject->ptr) > server.set_max_intset_entries)
                    setTypeConvert(subject,OBJ_ENCODING_HT);
                return 1;
            }
        } 
		else {
            /*不是整数,直接转为哈希*/
            setTypeConvert(subject,OBJ_ENCODING_HT);

            /* The set *was* an intset and this value is not integer
             * encodable, so dictAdd should always work. */
            serverAssert(dictAdd(subject->ptr,sdsdup(value),NULL) == DICT_OK);
            return 1;
        }
    } 
	else {
        serverPanic("Unknown set encoding");
    }
    return 0;
}

你可能感兴趣的:(Redis,redis,数据库,缓存)