前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Redis 学习笔记4 - 数据结构的使用

Redis 学习笔记4 - 数据结构的使用

作者头像
张云飞Vir
发布2020-04-02 10:53:25
3830
发布2020-04-02 10:53:25
举报
文章被收录于专栏:写代码和思考写代码和思考

1. 数据结构的使用

1.1 时间复杂度

谈到数据结构,一定会谈到 “时间复杂度”。

在计算机科学中,算法的时间复杂度是一个函数,它定性描述该算法的运行时间。 时间复杂度常用大O符号表述。 时间复杂度可被称为是渐近的,即考察输入值大小趋近无穷时的情况。

在 Redis 中,用它来表示,基于我们处理的数据的数量,命令执行的速度将会如何。

O(1)

最快的应该是 O(1) ,一个常量。sismember 命令,用于查询一个值是否属于一个集合,就是 O(1)。

sismember 是个强力的命令,很大一个原因就是快。Redis 中的大多数命令都是 O(1)。

O(log(N))

O(log(N)), 是第二快的,因为它需要扫描的区间范围越来越小。通过使用这种类型的切分和处理方法,一个非常大的集合仅需要做几次迭代就会被迅速的分解。

zadd 是一个 O(log(N)) 命令,N 表示在有序集合中的元素个数。

O(N)

O(N) 在表中查找没有做索引的列就是一个 O(N) 操作。就像用 ltrim 命令一样。但是,在 ltrim 中,N 不是列表的元素个数,而是要移除的元素的个数。

O(log(N)+M)

zremrangebyscore 用来从有序列表中删除那些权重在最小值和最高值之间的元素,拥有复杂度 O(log(N)+M)。

O(N+M*log(M))

sort 命令,的复杂度 O(N+M*log(M))

其他

还有两个比较常用的是 O(N^2) 和 O(C^N)。N 越大,性能越差。Redis 没有这种复杂度的命令

1.2 多 Key 查询

假如说,一个用户叫 users:leto 的用户,他的 基本信息 有 '{"id": 9001, "email": "leto@dune.gov", ...}' 如果,想通过用户 id, 和 email 都能快速检索到要怎么做?

方案1:使用 string 结构,存两份 即用 id ,和 email 作为键,存储两次 。示例:

代码语言:javascript
复制
set users:leto@dune.gov '{"id": 9001, "email": "leto@dune.gov", ...}'
set users:9001 '{"id": 9001, "email": "leto@dune.gov", ...}'

当用户很多时,这样的方式绝对是个噩梦,并且它们会占用你两倍内存空间。

方案2:使用哈希结构,用字段作为伪二阶索引

先用 string 结构存储基本信息,再用哈希结构 将 email 作为字段,id 作为值

代码语言:javascript
复制
set users:9001 '{"id": 9001, "email": "leto@dune.gov", ...}'
hset users:lookup:email leto@dune.gov 9001

那么,通过 id 获取 用户,我们可以用普通的 get:

代码语言:javascript
复制
get users:9001

想要通过 email 来获取用户,我们用 hget 配合 get (Ruby):

代码语言:javascript
复制
id = redis.hget('users:lookup:email', 'leto@dune.gov')
user = redis.get("users:#{id}")

这样的方式很节约 key 的数量。使用 伪二阶索引 建立了 映射。

1.3 引用和索引(References and Indexes)

上面的查询优化的例子,其实是 手工维护你的 value 之间的索引和 引用。这样的方式很常见。

在集合中维护索引:

代码语言:javascript
复制
sadd friends:leto ghanima paul chani jessica

上面标示了 leto 有 ghanima ,paul ,chani等几个 朋友。而 ghanima 这样的又可以指向具体的 用户信息。

再跟踪一下反向关系:

代码语言:javascript
复制
sadd friends_of:chani leto paul

上面标示了 chani 是 leto, paul的 朋友。

这些额外的索引值的处理和内存开销会让人吓到,我们通过使用额外的查询次数降低性能开销。其实关系型数据库也有一样的开销。

1.4 Round Trips and Pipelining

添加一个或多个记录 sadd 命令向集合中添加一个或多个记录:

代码语言:javascript
复制
sadd friends:vladimir piter
sadd friends:paul jessica leto "leto II" chani

接收多个参数 许多命令都可以接收一个或者多个参数,或者有一个带有多个参数的子查询

代码语言:javascript
复制
ids = redis.lrange('newusers', 0, 9)
redis.mget(*ids.map {|u| "users:#{u}"})

Redis 也支持管道 通常,一个客户端向 Redis 发送一个请求,然后在下次请求之前会一直等待返回。而用管道你可以发送一堆请求却不用等待它们的响应。这不单降低了网络开销,也在性能上有显著提高。

··· redis.pipelined do 9001.times do redis.incr('powerlevel') end end

···

批处理会被管道加速。

1.5 事务(Transactions)

Redis 所有的命令都是原子性的,包括那些一次可以执行多项操作的命令也一样。此外,在使用多命令的时候,Redis 支持事务。

Redis 确实是单线程的,这就是为什么每个命令都是原子性的原因。 一次只能执行一个命令

  • incr 实际上是一个 get 后面跟个 set
  • getset 设置一个新值之后返回原值
  • setnx 首先检查 key 是否存在,当它不存在的时候设值

事务的使用:

  • 首先你需要 multi 命令, 作为开始
  • 然后接下来是你希望作为一组事务执行的所有命令
  • 最后用 exec 来实际执行命令,或者用 discard 来放弃取消执行所有的命令

示例:

代码语言:javascript
复制
multi
hincrby groups:1percent balance -9000000000
hincrby groups:99percent balance 9000000000
exec

** watch**

代码语言:javascript
复制
redis.watch('powerlevel')
current = redis.get('powerlevel')
redis.multi()
redis.set('powerlevel', current + 1)
redis.exec()

如果另一个客户端在调用 watch 之后,改变了 powerlevel 的话,我们的事务将会失败。

1.6 Keys Anti-Pattern

keys 命令。该命令通过指定模式返回所有匹配的 key。这个命令看起来在某些情况下很适用,但是它绝对不应当用在产品代码中。因为它为了查找匹配的 key 会对所有的 key 做一个线性扫描,它很慢。

于是,考虑用哈希结构。就像我们可以用哈希来暴露二级索引那样,所以我们也可以用它来组织我们的数据:

代码语言:javascript
复制
hset bugs:1233 1 '{"id":1, "account": 1233, "subject": "..."}'
hset bugs:1233 2 '{"id":2, "account": 1233, "subject": "..."}'

为了取得一个账户下的所有 bug 标识符,我们只需要调用 hkeys bugs:1233。要删除指定 bug 我们可以 hdel bugs:1233 2,要删除账户的话我们可以通过 del bugs:1233 来删除 key。

END

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 数据结构的使用
    • 1.1 时间复杂度
      • O(1)
      • O(log(N))
      • O(N)
      • O(log(N)+M)
      • O(N+M*log(M))
      • 其他
    • 1.2 多 Key 查询
      • 1.3 引用和索引(References and Indexes)
        • 1.4 Round Trips and Pipelining
          • 1.5 事务(Transactions)
            • 1.6 Keys Anti-Pattern
            相关产品与服务
            云数据库 Redis
            腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档