redis中记录用户id用map好还是用hash好?

Redis创造了一种新的数据存储理念。有了redis,我们在面对单调的数据库时,不必再专注于如何把大象放进冰箱,而是利用redis灵活的数据结构和数据操作,为不同的大象搭建不同的冰箱。

Redis公共数据类型

redis最常用的数据类型主要包括以下五种:

线

混杂

目录

设置

排序集合

在详细描述这些数据类型之前,我们先通过一张图了解一下如何描述redis内存管理中这些不同的数据类型:

首先,redis使用一个redisobject对象来表示所有的键和值。Redisobject的主要信息如上图所示:type代表一。

什么数据类型是值对象?编码是不同数据类型在redis中的存储方式。例如,type=string表示值存储。

一个普通的字符串,那么对应的编码可以是raw或者int。如果是int,说明实际redis按照数值类型存储和表示这个字符串。当然,

前提是字符串本身可以用数值表示,比如“123”。

像“456”这样的字符串。

这里需要解释一下vm字段。只有打开redis的虚拟内存功能,这个字段才会真正分配内存。这个功能默认是关闭的,后面会详细介绍这个功能。及格

在上图中,我们可以发现redis使用redisobject来表示所有的键/值数据是对内存的浪费。当然,这些内存管理成本主要是给予

Redis为不同的数据类型提供了统一的管理接口,实际作者也提供了各种方法来帮助我们尽可能的节省内存,后面会详细讨论。

让我们逐一分析这五种数据类型的用途和内部实现:

线

常见命令:

设置、获取、减少、增加、管理等。

应用场景:

字符串是最常用的数据类型,普通的键/值存储都可以归入这一类,这里就不解释了。

实施模式:

存储在redis中的字符串默认是一个字符串,被redisobject引用。当遇到incr、decr等运算时,会转换成数值型进行计算。此时,redisobject的编码字段是int。

混杂

常见命令:

Hget、hset、hgetall等。

应用场景:

我们举一个简单的例子来描述hash的应用场景。例如,我们想存储一个用户信息对象数据,它包含以下信息:

用户id是要搜索的关键字,存储值用户对象包含姓名、年龄、生日等信息。如果它存储在一个公共的键/值结构中,有两种主要的存储方法:

第一种方法将用户id作为搜索关键字,并将其他信息封装到一个对象中,并以序列化的方式存储。这种方法的缺点是增加了序列化/反序列化的成本,当其中一个信息需要修改时,需要检索整个对象,修改操作需要保护并发性,引入cas等复杂问题。

第二种方法是将用户信息对象存储为有多少个成员就有多少个键-值对,并使用用户id+对应属性的名称作为惟一标识符来获取对应属性的值。虽然消除了序列化开销和并发问题,但是用户id是重复存储的,如果有大量这样的数据,内存浪费还是非常可观的。

那么redis提供的hash很好的解决了这个问题。redis的hash其实就是内部存储的值是一个hashmap,它提供了一个直接访问这个map成员的接口,如下图所示:

也就是说,密钥仍然是用户id,

Value是一个映射,这个映射的键是成员的属性名,value是属性值,这样就可以通过其内部映射的键直接修改和访问数据(内部映射的键在Redis中称为field)。

也就是通过key(用户id)+field(属性标签)。

可以操纵对应的属性数据,不需要重复存储数据,也不会带来序列化和并发修改控制的问题。它很好地解决了这个问题。

同时需要注意的是,redis提供了一个接口(hgetall),可以直接获取所有的属性数据,但是如果内部映射的成员很多,就涉及到遍历整个内部映射。

操作,由于redis单线程模型,这种遍历操作可能比较耗时,而其他客户端的请求完全没有响应,需要特别注意。

实施模式:

关于redis已经说过了

对应于hash的值实际上是一个hashmap。实际上,这里有两种不同的实现。当hash的成员数较少时,redis会使用类似一维数组的方式进行紧凑存储,而不是使用真正的hashmap结构和对应的值。

redisobject的编码是zipmap,当成员数量增加时会自动变成真正的hashmap,编码是ht。

目录

常见命令:

Lpush、rpush、lpop、rpop、lrange等。

应用场景:

雷迪斯

List有很多应用场景,也是redis最重要的数据结构之一。比如twitter的关注列表和粉丝列表,都可以通过redis的列表结构来实现,很好理解,这里不再赘述。

实施模式:

雷迪斯

list的实现是双向链表,可以支持反向搜索和遍历,更容易操作,但是带来了一些额外的内存开销。redis内部的许多实现,包括发送缓冲队列,也使用这种数据结构。

设置

常见命令:

Sadd,spop,sembers,sunion等。

应用场景:

雷迪斯

set提供的功能和list类似,但特别之处在于set可以自动复制。当你需要存储一个数据的列表,又不想要重复的数据时,set是一个很好的选择,set提供了一个判断成员是否在集合集合中的重要接口,这是list所不能提供的。

实施模式:

set的内部实现是一个。

值始终为null的Hashmap实际上是通过计算hash来快速排序的,这也是为什么set可以提供一种判断成员是否在集合中的方法。

排序集合

常见命令:

扎德、zrange、zrem、zcard等。

使用场景:

redis排序集的使用场景和set类似,只是set不自动排序,排序。

Set可以通过提供一个额外的参数score来对成员进行排序,而且是有序插入,也就是自动排序。当您需要有序且不重复的收藏列表时,您可以选择排序。

设置数据结构,比如twitter的public。