Redis系列(一)-Redis基础知识(一篇文章让你全面的了解Redis的介绍与安装以及常用的数据类型)

Nosql概述

1、Mysql单机年代

在这里插入图片描述
90年代,一个基本的网址访问量不会很大,单个数据库完全足够了。

那时候更多的使用html静态网页,服务器根本没有压力。

我们思考下,网站的瓶颈是什么?

1、数据量太大,一个机器存不了。

2、数据的索引(B + Tree) 一个机器也存不了。

3、访问量(读写混合),一个服务器也承受不住。

出现这3种情况,我们就必须要升级了。

2、Memcached缓存 + mysql + 垂直拆分(读写分离)

网址百分之80的情况都是在读取数据,每次查询都需要去查询数据库的话就非常的麻烦!所以说我们希望减轻数据库压力,我们可以使用缓存来保证效率!
在这里插入图片描述
缓存发展过程:优化数据结构和索引>文件缓存(IO)

3、分库分表 + 水平拆分 + Mysql集群

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CfS1CATl-1639365304419)(./image-20211103104836401.png)]
技术和业务在发展的同时对人的要求也越来越高了。

本质:数据库(读、写)

早些年mysql引擎是MyISAM:表锁,十分的影响效率。高并发下出现严重锁问题。

现在Mysql引擎是Innodb:行锁,很大程度的减少了锁的问题。

慢慢的我们开始使用分库分表来解决写的压力!Mysql在那个年代推出了表分区,但是这个并没有多少公司使用。后面推出了Mysql集群,很好的满足那个年代所有需求。

4、如今最近年代

2010–2021年之间,世界已经发生了翻天覆地的变化(定位、数据、音乐、热榜)

Mysql等关系型数据库就不够使用了,数据量太多,变化太快。

Mysql有的时候用它来处理较大的文件、博客、图片数据时,数据库表很大,效率低下。

如果有专门的数据库来处理这种数据,Mysql压力就变得小很多,大数据库的IO压力下,表几乎没法更大。

目前一个基本互联网项目的架构图:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VXWTILtS-1639365304420)(./image-20211103111850882.png)]

为什么要使用Nosql

用户的个人信息,社交网络,地理位置。用户自己产生的数据,用户日志等等爆发式增长!这个时候我们就需要使用NoSQL,数据量就可以很好的处理以上的问题了。

什么是NoSQL

Not Only Sql 不仅仅是sql

NoSQL仅仅是一个概念,泛指非关系型的数据库,区别于关系数据库,它们不保证关系数据的ACID特性。NoSQL是一项全新的数据库革命性运动,其拥护者们提倡运用非关系型的数据存储,相对于铺天盖地的关系型数据库运用,这一概念无疑是一种全新的思维的注入
解耦

NoSQL 特点:

1、方便扩展(数据之间没有关系,很好扩展)
2、大数据量高性能(Redis一秒写8万次,读11万,NoSQL的缓3、存记录级,是一种细粒度的缓存,性能会比较高)
4、数据类型是多样型的!(不需要事先设计数据库!随取随用!如果是数据量十分大的表,很多人就无法设计了)
5、传统的RDBMS(关系型数据库)和NoSQL区别

传统的 RDBMS
- 结构化组织
- SQL
- 数据和关系都存储在单独的表中
- 操作,数据定义语言
- 严格的一致性
- 基础的事务

NoSQL
- 不仅仅是数据
- 没有固定的语言
- 键值对存储,列存储,文档存储,图形数据库(社交关系)
- 最终一致性
- CAP定理和BASE(异地多活)
- 高性能、高可用、高可扩

了解:3V+3高

大数据时代的3V:主要是描述问题的

  • 海量Volume
  • 多样Variety
  • 实时Velocity

大数据时代的3高:主要是对程序的要求

  • 高并发
  • 高可拓
  • 高性能
Nosql的四大分类
KV键值对
  • 新浪:Redis
  • 美团:Redis + Tair
  • 阿里、百度:Redis + memecache
文档型数据库

bson格式和json一样的

MongoDB(必须要掌握)

  • MongoDB是一个基于分布式文件存储的数据库,C++编写的,主要用来处理大量的文档。
  • MongoDB是一个介于关系型数据库和非关系型数据库中间的产品。MongoDB是非关系型数据库中功能最丰富的、最像关系型数据库的!
列存储的数据库
  • HBase
  • 分布式文件系统
图关系数据库

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hOWyKdBO-1639365304420)(./image-20211103161418561.png)]
他不是存图形的,是存储关系的。比如:朋友圈,广告推荐等。

四种数据库的比较:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YxZTu6dS-1639365304421)(image-20211213103250449.png)]

Redis概述

Redis是什么

Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API
redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。

免费和开源!是当下最热门的NoSQL技术之一!也被人们称之为结构化数据库。

Redis能干嘛

1、内存存储、持久化、内存中是断电即失、所以持久化很重要。

2、效率高,可以用于高速缓存

3、发布订阅系统

4、地图信息分析

5、计时器、计数器(浏览量)

特性

1、多样的数据类型

2、持久化

3、集群

4、事务

学习中需要用到的东西

1、官网:https://redis.io/

2、中文网:https://www.redis.net.cn/

3、通过官网下载Redis

Windows安装

1、下载安装包:https://github.com/MicrosoftArchive/redis/releases

2、解压下载的安装包
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1BsyagzK-1639365304421)(./image-20211103170333997.png)]
3、双击redis-server.exe启动redis
在这里插入图片描述
4、使用redis客户端来连接redis

双击刚才解压的redis目录里的redis-cli.exe,输入ping命令提示PONG表示连接成功并可以存储字符串
在这里插入图片描述
虽然Windows使用redis比较简单,但是我们还是推荐Linux安装Redis使用。

Linux安装

1、官网下载获取安装包:redis-6.2.6.tar.gz
在这里插入图片描述
2、上传下载好的redis安装包到linux服务器

[root@VM-0-16-centos resource]# pwd
/home/hecan/redis/resource
[root@VM-0-16-centos resource]# ls
redis-6.2.6.tar.gz
[root@VM-0-16-centos resource]#

3、移动并解压安装包,程序建议放在opt目录下

# 移动安装包到opt目录
[root@VM-0-16-centos resource]# cp redis-6.2.6.tar.gz /opt/
# 解压
[root@VM-0-16-centos opt]# tar zxvf redis-6.2.6.tar.gz 
[root@VM-0-16-centos opt]# ls
containerd  knem-1.1.4.90mlnx1  mellanox  redis-6.2.6  redis-6.2.6.tar.gz  rh

4、进入redis-6.2.6你会发现一个redis的配置文件redis.conf
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oPNVGHXx-1639365304424)(./image-20211104103549760.png)]
5、安装一下gcc-c++基础环境

[root@VM-0-16-centos redis-6.2.6]# yum install gcc-c++
Loaded plugins: fastestmirror, langpacks
Determining fastest mirrors
docker-ce-stable                                                                                                                                                  | 3.5 kB  00:00:00     
epel                                                                                                                                                              | 4.7 kB  00:00:00     
extras                                                                                                                                                            | 2.9 kB  00:00:00     
os                                                                                                                                                                | 3.6 kB  00:00:00     
updates                                                                                                                                                           | 2.9 kB  00:00:00     
(1/4): docker-ce-stable/7/x86_64/primary_db                                                                                                                       |  67 kB  00:00:00     
(2/4): epel/7/x86_64/updateinfo                                                                                                                                   | 1.0 MB  00:00:00     
(3/4): epel/7/x86_64/primary_db                                                                                                                                   | 7.0 MB  00:00:01     
(4/4): updates/7/x86_64/primary_db                                                                                                                                |  12 MB  00:00:01     
Package gcc-c++-4.8.5-44.el7.x86_64 already installed and latest version
Nothing to do

6、在redsi目录下执行make和make install命令,把所有需要环境配置都准备上

[root@VM-0-16-centos redis-6.2.6]# make
cd src && make all
make[1]: Entering directory `/opt/redis-6.2.6/src'
    CC Makefile.dep
make[1]: Leaving directory `/opt/redis-6.2.6/src'
make[1]: Entering directory `/opt/redis-6.2.6/src'
......

# 执行make install发现所有的环境都已经安装好了
[root@VM-0-16-centos redis-6.2.6]# make install
cd src && make install
make[1]: Entering directory `/opt/redis-6.2.6/src'

Hint: It's a good idea to run 'make test' ;)

    INSTALL redis-server
    INSTALL redis-benchmark
    INSTALL redis-cli
make[1]: Leaving directory `/opt/redis-6.2.6/src'
[root@VM-0-16-centos redis-6.2.6]# 

7、redis的默认安装路径/usr/local/bin/

[root@VM-0-16-centos redis-6.2.6]# cd /usr/local/bin/
[root@VM-0-16-centos bin]# ll
total 19892
-rwxr-xr-x 1 root root 1001112 Aug  5  2020 busybox-x86_64
-rwxr-xr-x 1 root root 4829520 Nov  4 10:43 redis-benchmark
lrwxrwxrwx 1 root root      12 Nov  4 10:43 redis-check-aof -> redis-server
lrwxrwxrwx 1 root root      12 Nov  4 10:43 redis-check-rdb -> redis-server
-rwxr-xr-x 1 root root 5003800 Nov  4 10:43 redis-cli
lrwxrwxrwx 1 root root      12 Nov  4 10:43 redis-sentinel -> redis-server
-rwxr-xr-x 1 root root 9524072 Nov  4 10:43 redis-server

8、将刚才找到的redis.conf配置文件复制到当前/usr/local/bin/目录下,我们之后就使用这个配置文件进行启动。

[root@VM-0-16-centos bin]# cp /opt/redis-6.2.6/redis.conf ./
[root@VM-0-16-centos bin]# ll
total 19984
-rwxr-xr-x 1 root root 1001112 Aug  5  2020 busybox-x86_64
-rwxr-xr-x 1 root root 4829520 Nov  4 10:43 redis-benchmark
lrwxrwxrwx 1 root root      12 Nov  4 10:43 redis-check-aof -> redis-server
lrwxrwxrwx 1 root root      12 Nov  4 10:43 redis-check-rdb -> redis-server
-rwxr-xr-x 1 root root 5003800 Nov  4 10:43 redis-cli
-rw-r--r-- 1 root root   93724 Nov  4 10:48 redis.conf
lrwxrwxrwx 1 root root      12 Nov  4 10:43 redis-sentinel -> redis-server
-rwxr-xr-x 1 root root 9524072 Nov  4 10:43 redis-server

9、redis默认不是后台启动运行的,我们需要修改配置文件将redis改为后台运行。

# 编辑配置文件,找到配置文件里面的daemonize改为yes。
[root@VM-0-16-centos bin]# vim redis.conf 

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W5oww6qI-1639365304424)(./image-20211104105348003.png)]
10、启动redis服务

在redis的安装目录下找到redis-server

[root@VM-0-16-centos bin]# redis-server ./redis.conf 
[root@VM-0-16-centos bin]# ps -ef|grep redis
root     11954     1  0 11:01 ?        00:00:00 redis-server 127.0.0.1:6379
root     12048  2447  0 11:01 pts/0    00:00:00 grep --color=auto redis

11、使用redis客户端redis-cli连接下redis-server测试下,是否已经正确的启动redis

[root@VM-0-16-centos bin]# redis-cli -p 6379
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> set name hecan
OK
127.0.0.1:6379> get name
"hecan"

12、关闭redis,再次查看redis进程是否存在

# 在redis-cli下执行shutdown命令
127.0.0.1:6379> shutdown
not connected> exit
[root@VM-0-16-centos bin]# ps -ef|grep redis
root     13528  2447  0 11:09 pts/0    00:00:00 grep --color=auto redis
[root@VM-0-16-centos bin]# 
性能测试

我们发现在redis的安装目录下有一个redis-benchmark ,它是一个官方自带的压力测试工具!

redis-benchmark [命令参数]

图片来自菜鸟教程:
在这里插入图片描述
我们来简单的测试一下:测试100个并发连接,每一个并发请求10W

命令:redis-benchmark -h localhost -p 6379 -c 100 -n 100000
在这里插入图片描述
如何查看分析呢?
在这里插入图片描述

基础知识

redis 默认有16个数据库,默认使用的是第0个。
在这里插入图片描述

命令:redis数据库的切换
# 命令:select [第几个数据库]
127.0.0.1:6379> select 3
OK
127.0.0.1:6379[3]> 

不同的数据库都是独立的可以存不同的值

127.0.0.1:6379> select 3
OK
127.0.0.1:6379[3]> dbsize
(integer) 0
127.0.0.1:6379[3]> set name hecan2
OK
127.0.0.1:6379[3]> dbsize
(integer) 1
127.0.0.1:6379[3]> select 7
OK
127.0.0.1:6379[7]> dbsize
(integer) 0
127.0.0.1:6379[7]> select 3
OK
127.0.0.1:6379[3]> dbsize
(integer) 1
命令:查看当前数据库所有的key
127.0.0.1:6379[3]> keys *
1) "name"
127.0.0.1:6379[3]> 
命令:清空当前数据库信息
127.0.0.1:6379[3]> flushdb
OK
127.0.0.1:6379[3]> keys *
(empty array)
127.0.0.1:6379[3]> 
命令:清空所有的数据库
127.0.0.1:6379[3]> keys *
1) "name"
2) "age"
127.0.0.1:6379[3]> flushall
OK
127.0.0.1:6379[3]> keys *
(empty array)
127.0.0.1:6379[3]>
Redis是单线程的

明白Redis是很快的,官方表示,Redis是基于内存操作的,CPU不是Redis性能的瓶颈,Redis的瓶颈是根据机器的内存和网络带宽,既然可以使用单线程实现,就使用单线程了。

Redis为什么单线程还这么快?

  1. 误区1:高性能的服务器一定是多线程的?
  2. 误区2:多线程(CPU上下文会切换!)一定比单线程效率高??

核心: redis是将所有的数据全部存放在内存中的,所以说使用单线程去操作效率就是最高的,多线程(CPU会上下文切换:耗时操作!)对于内存系统来说,如果没有上下文切换,效率就是最高的,多次读写都是在一个cpu上的,在内存情况下,这个就是最优的方案!

五大基本的数据类型

官网说明:

Redis是一个开源(BSD许可),内存存储的数据结构服务器,可用作数据库,高速缓存消息队列代理。它支持字符串、哈希表、列表、集合、有序集合,位图,hyperloglogs等数据类型。内置复制、Lua脚本、LRU收回、事务以及不同级别磁盘持久化功能,同时通过Redis Sentinel提供高可用,通过Redis Cluster提供自动分区。

Redis-key
127.0.0.1:6379[3]> set name hecan
OK
127.0.0.1:6379[3]> set age 29
OK
# keys * 获取当前数据库的所有key值
127.0.0.1:6379[3]> keys *
1) "name"
2) "age"

# 判断当前数据库是否存在key=name的键值对,返回1表示存在,返回0表示不存在
127.0.0.1:6379[3]> exists name
(integer) 1
127.0.0.1:6379[3]> exists name1
(integer) 0

# 移除key值为name的键值对数据
127.0.0.1:6379[3]> move name 1
(integer) 1
127.0.0.1:6379[3]> keys *

# 设置key值的过期时间, 单位是秒
127.0.0.1:6379[3]> expire name 10
(integer) 1

# 查看当前key的剩余时间
127.0.0.1:6379[3]> ttl name
(integer) 7
127.0.0.1:6379[3]> 
127.0.0.1:6379[3]> ttl name
(integer) 3
127.0.0.1:6379[3]> ttl name
(integer) 2
127.0.0.1:6379[3]> ttl name
(integer) 1
127.0.0.1:6379[3]> ttl name
(integer) -2
127.0.0.1:6379[3]> get name

# 查看key值存放的类型
127.0.0.1:6379[3]> type name
string
String(字符串)
set:设置key和key值

设置一个key1的字符串v1

127.0.0.1:6379[3]> set key1 v1			# 设置一个key1的字符串v1
OK
get:跟据key获取key值

根据key1获取v1

127.0.0.1:6379[3]> get key1				# 根据key1获取v1
"v1"
exists:判断key是否存在

判断一个key1是否存在,1表示存在,0表示不存在

127.0.0.1:6379[3]> keys *
1) "key1"
127.0.0.1:6379[3]> exists key1			# 判断一个key是否存在
(integer) 1
127.0.0.1:6379[3]> exists name1
(integer) 0
append:key值后追加字符串

在以存在的key1值后面追加字符串hello,如果当前key不存在,这和set一样的(新建一个key)

127.0.0.1:6379[3]> set key1 v1			# 设置一个key1的字符串v1
OK
127.0.0.1:6379[3]> get key1				# 根据key1获取v1
"v1"
127.0.0.1:6379[3]> append key1 hello
(integer) 7
127.0.0.1:6379[3]> get key1
"v1hello"
incr:数字自增1

数字自增1,类似于 i+=1

127.0.0.1:6379[3]> set count 0			# 初始数字为0
OK
127.0.0.1:6379[3]> get count
"0"
127.0.0.1:6379[3]> incr count			# 数字自动加1
(integer) 1
127.0.0.1:6379[3]> incr count
(integer) 2
127.0.0.1:6379[3]> get count
"2"
decr:数字自减1

数字自减1

127.0.0.1:6379[3]> get count
"2"
127.0.0.1:6379[3]> decr count			# 数字自动减1
(integer) 1
127.0.0.1:6379[3]> decr count
(integer) 0
127.0.0.1:6379[3]> get count
"0"
incrby:数字按照步数增加

数字按照步数增加10

127.0.0.1:6379[3]> get count
"-1"
127.0.0.1:6379[3]> incrby count 10		# 数字加10
(integer) 9
127.0.0.1:6379[3]> get count
"9"
decrby:数字按照步数减少

数字按照步数减少10

127.0.0.1:6379[3]> get count
"9"
127.0.0.1:6379[3]> decrby count 10		# 数字减10
(integer) -1
127.0.0.1:6379[3]> get count
"-1"
getrange:字符串范围截取

截取下标0-3的字符串

127.0.0.1:6379[3]> set name "hello,hecan"	# 设置name的值
OK
127.0.0.1:6379[3]> get name
"hello,hecan"
127.0.0.1:6379[3]> getrange name 0 3		# 截取下标0-3的字符串
"hell"

查看整个字符串

127.0.0.1:6379[3]> getrange name 0 -1		# 查看整个字符串
"hello,hecan"
setrange:替换字符串
127.0.0.1:6379[3]> set key2 abcdefg			# 设置key2的值
OK
127.0.0.1:6379[3]> get key2
"abcdefg"
127.0.0.1:6379[3]> setrange key2 1 XX		# 替换指定位置开始的字符串
(integer) 7
127.0.0.1:6379[3]> get key2
"aXXdefg"
setex:设置过期时间

set with expire,单位秒。设置key3 过期时间为60秒

127.0.0.1:6379> setex key3 60 v3
OK
127.0.0.1:6379> ttl key3
(integer) 55
127.0.0.1:6379> ttl key3
(integer) 50
127.0.0.1:6379> ttl key3
(integer) 48
127.0.0.1:6379> ttl key3
(integer) 32
127.0.0.1:6379> ttl key3
(integer) -2
127.0.0.1:6379> ttl key3
setnx:不存在再设置

set if not exist。设置mykey值为v1,返回1表示成功。再设置mykey值为v2,返回0表示失败。这种场景再分布式锁中很常用。(如何mykey不存在则设置成功,如果存在设置失败)

127.0.0.1:6379> setnx mykey v1
(integer) 1
127.0.0.1:6379> get mykey
"v1"
127.0.0.1:6379> setnx mykey v2
(integer) 0
127.0.0.1:6379> get mykey
"v1"
127.0.0.1:6379> 
mset:批量设置key值

批量设置key1,key2,key3

127.0.0.1:6379> mset key1 v1 key2 v2 key3 v3
OK
127.0.0.1:6379> keys *
1) "key1"
2) "key3"
3) "key2"
mget:批量获取key值

批量获取key1,key2,key3

127.0.0.1:6379> mget key1 key2 key3
1) "v1"
2) "v2"
3) "v3"
msetnx:批量设置(存在key失败)

批量设置key值,如果存在则全部回滚失败。我们在key1,key2,key3存在的情况下设置key1,key4

127.0.0.1:6379> mget key1 key2 key3
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> msetnx key1 vv1 key4 v4
(integer) 0
127.0.0.1:6379> keys *
1) "key1"
2) "key3"
3) "key2"
127.0.0.1:6379> get key1
"v1"
设置一个对象:json字符串

在redis里面存放一个user:1对象,值为json字符串来保存一个对象

这里的key是一个伪设计:user:{id}:{filed}。如此设计在redis里面是可行的。

127.0.0.1:6379> set user:1 {name:hecan,age:29}
127.0.0.1:6379> get user:1
"{name:hecan,age:29}"
设置一个对象:批量字段设置
127.0.0.1:6379> mset user:1:name hecan user:1:age 2
OK
127.0.0.1:6379> get user:1:name
"hecan"
127.0.0.1:6379> mget user:1:name
1) "hecan"
127.0.0.1:6379> mget user:1:name user:1:age
1) "hecan"
2) "2"
getset:先获取(get)再设置(set)

首先先获取key值,然后再设置key的值

127.0.0.1:6379> getset name hecan	# 如果不存在值,返回null并设置新的值
(nil)
127.0.0.1:6379> get name
"hecan"
127.0.0.1:6379> getset name hecan2	# 如果存在值,返回当前值并设置新的值
"hecan"
127.0.0.1:6379> get name
"hecan2"
127.0.0.1:6379> 
List:(列表)

再redis里面我们可以把redis玩成一个栈(先进后出)、队列(先进先出)、阻塞队列。

所有的list命令都是以:l 开头的

添加列表元素

lpush:从列表的头部(左侧Left)放入元素

127.0.0.1:6379> lpush list one		# 将一个值或多个值插入列表的头部(左)
(integer) 1
127.0.0.1:6379> lpush list two
(integer) 2
127.0.0.1:6379> lpush list three
(integer) 3
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"

rpush:从列表的尾部(右侧right)放入元素

127.0.0.1:6379> rpush list hecan	# 将一个值或多个值插入列表的尾部(右)
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
4) "hecan"
查看列表元素

lrange:查询所有的列表元素

127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"

lrange:查询指定下标的列表元素

127.0.0.1:6379> lrange list 0 1
1) "three"
2) "two"
移除列表中的元素

lpop:从左侧移除列表中的元素

127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
4) "hecan"
127.0.0.1:6379> lpop list			# 移除左侧的three元素
"three"
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"
3) "hecan"

rpop:从右侧移除列表中的元素

127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"
3) "hecan"
127.0.0.1:6379> rpop list			# 移除右侧的hecan元素
"hecan"
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"

lrem:移除指定个数的内容元素

127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "three"
3) "two"
4) "one"
127.0.0.1:6379> lrem list 1 one		# 移除list列表里面的一个one
(integer) 1
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "three"
3) "two"
127.0.0.1:6379> lrem list 2 three	# # 移除list列表里面的两个three
(integer) 2
127.0.0.1:6379> lrange list 0 -1
1) "two"
通过下标获取单个元素

lindex:通过列表的下标值获取对应的元素

127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"
127.0.0.1:6379> lindex list 0		# 通过列表的下标值获取对应的元素
"two"
127.0.0.1:6379> lindex list 1
"one"
127.0.0.1:6379> 

查看列表中元素的个数

llen:查看列表的长度

127.0.0.1:6379> llen list
(integer) 2
截取部分列表元素

ltrim:通过下标截取列表元素,并覆盖原来的列表

127.0.0.1:6379> lrange mylist 0 -1
1) "one"
2) "one1"
3) "one2"
4) "one3"
127.0.0.1:6379> ltrim mylist 1 2		# 截取下标1~2的列表元素
OK
127.0.0.1:6379> lrange mylist 0 -1
1) "one1"
2) "one2"
将列表的元素移动到另一个列表

rpoplpush:将一个列表的尾部(右侧)元素移动到另外一个列表的左侧(头部)

127.0.0.1:6379> lrange mylist 0 -1
1) "one"
2) "one1"
3) "one2"
4) "one3"
5) "one4"
127.0.0.1:6379> rpoplpush mylist myotherlist	# 将mylist列表的one4(右侧元素)移动到myotherlist列表中(左侧插入)
"one4"
127.0.0.1:6379> lrange mylist 0 -1
1) "one"
2) "one1"
3) "one2"
4) "one3"
127.0.0.1:6379> lrange myotherlist 0 -1
1) "one4"
127.0.0.1:6379> rpoplpush mylist myotherlist	# # 将mylist列表的one3(右侧元素)移动到myotherlist列表中(左侧插入)
"one3"
127.0.0.1:6379> lrange mylist 0 -1
1) "one"
2) "one1"
3) "one2"
127.0.0.1:6379> lrange myotherlist 0 -1
1) "one3"
2) "one4"
指定下标更新列表里面的元素

lset:根据下标更新列表里面的元素,如果下标位置不存在,提示报错,如果存在,则更新成功

127.0.0.1:6379> exists list				# 判断列表是否存在
(integer) 0
127.0.0.1:6379> lset list 0 item		# 更新下标0的元素为item,如果下标位置不存在,提示报错
(error) ERR no such key
127.0.0.1:6379> lpush list value1
(integer) 1 
127.0.0.1:6379> lrange list 0 -1
1) "value1"
127.0.0.1:6379> lset list 0 item		# 更新下标0的元素为item,如果下标位置存在,提示成功
OK
127.0.0.1:6379> lrange list 0 -1		# 查看更改成功value1-->item
1) "item"
127.0.0.1:6379> lset list 1 item2		# 更新下标1的元素为item2,如果下标位置不存在,提示报错
(error) ERR index out of range
127.0.0.1:6379>  
往指定元素前后插入新元素

linsert:linsert [key] befor/after [指定元素] [新元素],再指定的元素前或后插入一个新的元素

127.0.0.1:6379> lpush list hello
(integer) 1
127.0.0.1:6379> rpush list world
(integer) 2
127.0.0.1:6379> lrange list 0 -1					# 成功构造了一个list列表
1) "hello"
2) "world"
127.0.0.1:6379> linsert list before world hello1	# 在list列表的world前面插入一个hello1元素
(integer) 3
127.0.0.1:6379> lrange list 0 -1					# 查看成功插入了hello1
1) "hello"
2) "hello1"
3) "world"
127.0.0.1:6379> linsert list after world world2		# 在list列表的world后面插入一个world2元素
(integer) 4
127.0.0.1:6379> lrange list 0 -1					# 查看成功插入了world2
1) "hello"
2) "hello1"
3) "world"
4) "world2"
127.0.0.1:6379> 
小结
  1. 列表实际上是一个链表的结构,before 节点 after ,left,right都可以插入值。
  2. 如果列表的key不存在,lpush则创建新的链表。
  3. 如果列表key存在,lpush则新增元素。
  4. 如果移除了所有的值,空链表,也表示不存在。
  5. 在两边插入或者改动值,效率最高!中间元素相对效率低一点。

实现队列:左插右取 --> lpush rpop

实现栈:左插左取 --> lpush lpop

Set(集合)

set中的值是不可以重读的,无序唯一

集合中添加元素

sadd:向set集合中添加元素

127.0.0.1:6379> sadd myset hello		# 向myset中添加元素hello
(integer) 1
127.0.0.1:6379> sadd myset hecan		# 向myset中添加元素hecan
(integer) 1
127.0.0.1:6379> sadd myset hecan2		# 向myset中添加元素hecan2
(integer) 1
127.0.0.1:6379> SMEMBERS myset
1) "hello"
2) "hecan2"
3) "hecan"
127.0.0.1:6379> SISMEMBER myset hello
(integer) 1
127.0.0.1:6379> SISMEMBER myset hecan3
(integer) 0
127.0.0.1:6379> 

查看集合中的元素

smembers:查看集合中所有的元素

127.0.0.1:6379> sadd myset hello		# 向myset中添加元素hello
(integer) 1
127.0.0.1:6379> sadd myset hecan		# 向myset中添加元素hecan
(integer) 1
127.0.0.1:6379> sadd myset hecan2		# 向myset中添加元素hecan2
(integer) 1
127.0.0.1:6379> SMEMBERS myset			# 查看myset中添加的所有元素
1) "hello"
2) "hecan2"
3) "hecan"
集合中是否存在某元素

sismembers:集合中是否存在某元素,存在返回1,不存在返回0

127.0.0.1:6379> SMEMBERS myset
1) "hello"
2) "hecan2"
3) "hecan"
127.0.0.1:6379> SISMEMBER myset hello	# 集合中是否存在hello
(integer) 1
127.0.0.1:6379> SISMEMBER myset hecan3	# 集合中是否存在hecan3
(integer) 0
获取集合元素个数

scard:获取set集合元素个数

127.0.0.1:6379> SMEMBERS myset
1) "hello"
2) "hecan2"
3) "hecan"
127.0.0.1:6379> scard myset		# 获取myset集合元素个数
(integer) 3
127.0.0.1:6379> 
移除集合中的元素

srem:根据元素的内容移除集合中的元素

127.0.0.1:6379> SMEMBERS myset
1) "hello"
2) "hecan2"
3) "hecan"
127.0.0.1:6379> SREM myset hello		# 移除myset集合中的hello元素
(integer) 1
127.0.0.1:6379> SMEMBERS myset
1) "hecan2"
2) "hecan"
127.0.0.1:6379> 
随机获取集合中的指定个数元素

SRANDMEMBER:随机获取set集合里面的指定个数的元素,抽奖

127.0.0.1:6379> SMEMBERS myset
1) "hecan3"
2) "hecan1"
3) "hecan2"
4) "hecan"
5) "hecan4"
127.0.0.1:6379> SRANDMEMBER myset	# 随机获取myset集合里的一个元素
"hecan3"
127.0.0.1:6379> SRANDMEMBER myset	# 随机获取myset集合里的一个元素
"hecan"
127.0.0.1:6379> SRANDMEMBER myset 2	# 随机获取myset集合里的两个元素
1) "hecan4"
2) "hecan3"
127.0.0.1:6379> SRANDMEMBER myset 2	# 随机获取myset集合里的两个元素
1) "hecan4"
2) "hecan"
127.0.0.1:6379> SRANDMEMBER myset 3	# 随机获取myset集合里的三个元素
1) "hecan2"
2) "hecan4"
3) "hecan3"
127.0.0.1:6379> SRANDMEMBER myset 3	# 随机获取myset集合里的三个元素
1) "hecan2"
2) "hecan4"
3) "hecan"
随机移除集合中的某个元素

spop:随机移除集合里面的某个元素

127.0.0.1:6379> SMEMBERS myset
1) "hecan1"
2) "hecan2"
3) "hecan3"
4) "hecan4"
5) "hecan"
127.0.0.1:6379> SPOP myset		# 随机移除myset集合里面的某个元素
"hecan2"
127.0.0.1:6379> SPOP myset		# 随机移除myset集合里面的某个元素
"hecan1"
127.0.0.1:6379> SMEMBERS myset
1) "hecan3"
2) "hecan4"
3) "hecan"
127.0.0.1:6379> 
将集合中某个元素移动到另一个集合

smove:将一个集合中的某一个元素移动到另外一个集合中

127.0.0.1:6379> sadd myset hecan1		# 向myset集合中添加hecan1
(integer) 1
127.0.0.1:6379> sadd myset hecan2		# 向myset集合中添加hecan2
(integer) 1
127.0.0.1:6379> sadd myset hecan3		# 向myset集合中添加hecan3
(integer) 1
127.0.0.1:6379> sadd myset hecan4		# 向myset集合中添加hecan4
(integer) 1
127.0.0.1:6379> SMEMBERS myset
1) "hecan4"
2) "hecan3"
3) "hecan1"
4) "hecan2"
127.0.0.1:6379> smove myset myset2 hecan2 # 将myset中的hecan2元素移动到myset2中
(integer) 1
127.0.0.1:6379> SMEMBERS myset			# 查看myset所有的元素
1) "hecan4"
2) "hecan3"
3) "hecan1"
127.0.0.1:6379> SMEMBERS myset2			# 查看myset2所有的元素
1) "hecan2"
127.0.0.1:6379> 
获取两个集合的差集、交集、并集

SDIFF:获取两个集合的差集,SDIFF key1 key2,显示key1的差值

SINTER:获取两个集合的交集,SINTER key1 key2

SUNION :获取两个集合的并集,SUNION key1 key2

127.0.0.1:6379> sadd key1 a
(integer) 1
127.0.0.1:6379> sadd key1 b
(integer) 1
127.0.0.1:6379> sadd key1 c
(integer) 1
127.0.0.1:6379> sadd key2 c
(integer) 1
127.0.0.1:6379> sadd key2 d
(integer) 1
127.0.0.1:6379> sadd key2 f
(integer) 1
127.0.0.1:6379> SMEMBERS key1		# 设置好key1集合的值
1) "c"
2) "a"
3) "b"
127.0.0.1:6379> SMEMBERS key2		# 设置好key2集合的值
1) "c"
2) "f"
3) "d"
127.0.0.1:6379> SDIFF key1 key2		# 获取key1和key2的差集,显示key1差值
1) "a"
2) "b"
127.0.0.1:6379> SINTER key1 key2	# 获取key1和key2的交集,微博共同好友案例
1) "c"
127.0.0.1:6379> SUNION key1 key2	# 获取key1和key2的并集
1) "c"
2) "f"
3) "a"
4) "b"
5) "d"
127.0.0.1:6379> 
Hash(哈希)

Map集合,key-map --> key - <key, value>,哈希本质和String 类型没有太大区别

添加哈希元素

hset:添加一个哈希元素,字段不存在添加,存在覆盖

127.0.0.1:6379> hset myhash field1 hecan1	# 添加一个map元素,field1 = hecan1
(integer) 1
127.0.0.1:6379> hget myhash field1			# 查看Map集合的field1字段
"hecan1"

hmset:批量添加哈希元素,字段不存在添加,存在覆盖

127.0.0.1:6379> hmset myhash f1 v1 f2 v2	# 批量添加哈希元素
OK
127.0.0.1:6379> hget myhash f1
"v1"
127.0.0.1:6379> hget myhash f2
"v2"

hsetnx:添加哈希元素,字段不存在添加返回1,字段存在添加失败返回0

127.0.0.1:6379> HSETNX myhash f4 v4		# 如何字段不存在则设置成功返回1
(integer) 1
127.0.0.1:6379> HSETNX myhash f2 vv2	# 如何字段存在则设置成功返回0
(integer) 0
127.0.0.1:6379> 
查看哈希元素

hget:根据一个具体的field查看对应的字段值

127.0.0.1:6379> hset myhash field1 hecan1	# 添加一个map元素,field1 = hecan1
(integer) 1
127.0.0.1:6379> hget myhash field1			# 查看Map集合的field1字段
"hecan1"

hmget :批量获取哈希里面的多个字段

127.0.0.1:6379> hmset myhash f1 v1 f2 v2	# 批量添加哈希元素
OK
127.0.0.1:6379> hmget myhash f1 f2			# 批量获取哈希元素
1) "v1"
2) "v2"

hgetall:获取全部得哈希值

127.0.0.1:6379> hgetall myhash # 以key-value得形式展示所有得值
1) "field1"
2) "hecan1"
3) "f1"
4) "v1"
5) "f2"
6) "v2"
删除哈希值

hdel:hdel [key] [field],根据具体得字段删除哈希值

127.0.0.1:6379> hgetall myhash
1) "field1"
2) "hecan1"
3) "f1"
4) "v1"
5) "f2"
6) "v2"
127.0.0.1:6379> hdel myhash f1		# 删除myhash的f1字段值
(integer) 1
127.0.0.1:6379> hgetall myhash
1) "field1"
2) "hecan1"
3) "f2"
4) "v2"
获取哈希的键值对长度

hlen:Hlen [key],获取哈希的键值对长度

127.0.0.1:6379> hgetall myhash
1) "field1"
2) "hecan1"
3) "f2"
4) "v2"
127.0.0.1:6379> Hlen myhash
(integer) 2
127.0.0.1:6379> 
判断哈希中的指定field是否存在

hexists:hexists [key] [field],1存在,0不存在

127.0.0.1:6379> HEXISTS myhash f2
(integer) 1
127.0.0.1:6379> HEXISTS myhash f1
(integer) 0
127.0.0.1:6379> 
只获取哈希的field或者值

hkeys:hkeys [key] 获取哈希的所有field字段 hvals:hvals [key] 获取哈希的所有field字段值

127.0.0.1:6379> HKEYS myhash
1) "field1"
2) "f2"
127.0.0.1:6379> HVALS myhash
1) "hecan1"
2) "v2"
127.0.0.1:6379> 
哈希字段值指定自增量和指定自减量

hincrby:hincrby [key] [field] [指定增量],指定哈希某一个字段增加多少或者减少多少

127.0.0.1:6379> hset myhash f3 1
(integer) 1
127.0.0.1:6379> HINCRBY myhash f3 2		# 指定增量
(integer) 3
127.0.0.1:6379> HINCRBY myhash f3 -1	# 指定减量
使用哈希存储对象

使用哈希来存储对象,使用方式可以参考上面的string(字符串的方式)

hmset:使用哈希存放对象并批量设置对象多个字段和值

hmget:批量查看哈希里面对象的属性值

127.0.0.1:6379> hmset user:1 name hecan age 29 height 170	# 批量设置对象属性
OK
127.0.0.1:6379> HVALS user:1	# 查看对象得属性值
1) "hecan"
2) "29"
3) "170"
127.0.0.1:6379> hmget user:1 name age height	# 批量查看对象得属性值
1) "hecan"
2) "29"
3) "170"
Zset(有序集合)

在set的基础上,增加了一个score1(排序)值,set k1 v1 Zset k1 score1 v1

添加Zset集合元素

Zadd [key] [score] [value]

127.0.0.1:6379> Zadd myset 1 one 2 three 3 two	# 按照1、2、3顺序设置值
(integer) 3
127.0.0.1:6379> zrange myset 0 -1				# 查看myset有序集合
1) "one"
2) "three"
3) "two"
127.0.0.1:6379> 
Zset元素排序

升序:ZRANGEBYSCORE [key] -inf +inf

-inf:负无穷大

+inf:正无穷大

降序:ZREVRANGE [key] 0 -1

127.0.0.1:6379> Zadd salary 1000 zhangsan1000		# 添加用户和薪水
(integer) 1
127.0.0.1:6379> Zadd salary 3000 zhangsan3000		# 添加用户和薪水
(integer) 1
127.0.0.1:6379> Zadd salary 2000 zhangsan2000		# 添加用户和薪水
(integer) 1
127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf		# 负无穷到正无穷,升序排序
1) "zhangsan1000"
2) "zhangsan2000"
3) "zhangsan3000"
127.0.0.1:6379> 
127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf withscores # 查看集合负无穷到正无穷,升序排序,并输出score
1) "zhangsan1000"
2) "1000"
3) "zhangsan2000"
4) "2000"
5) "zhangsan3000"
6) "3000"
127.0.0.1:6379> ZRANGEBYSCORE salary -inf 2000 withscores	# 查看集合负无穷到2000(score < 2000),升序排序,并输出score
1) "zhangsan1000"
2) "1000"
3) "zhangsan2000"
4) "2000"
127.0.0.1:6379> ZREVRANGE salary 0 -1	# ZREVRANGE降序排序
1) "zhangsan3000"
2) "zhangsan2000"
127.0.0.1:6379> 
删除元素

Zrem [key] [集合中的元素]

127.0.0.1:6379> Zrange salary 0 -1
1) "zhangsan1000"
2) "zhangsan2000"
3) "zhangsan3000"
127.0.0.1:6379> Zrem salary zhangsan1000	# 移除salary中的zhangsan1000元素
(integer) 1
127.0.0.1:6379> Zrange salary 0 -1
1) "zhangsan2000"
2) "zhangsan3000"
127.0.0.1:6379> 
查看元素的数量

Zcard [key]

127.0.0.1:6379> Zcard salary	# 获取有序集合中的个数
(integer) 2
127.0.0.1:6379> 
获取指定区间的元素数量

Zcount [key] [min] [max]

127.0.0.1:6379> Zadd myset 1 hecan1 2 hecan2 3 hecan3 4 hecan4	# 设置myset有序集合元素
(integer) 4
127.0.0.1:6379> Zcount myset 1 3	# 查看1-3之间元素个数
(integer) 3
127.0.0.1:6379> Zcount myset 1 4	# 查看1-4之间元素个数
(integer) 4
127.0.0.1:6379> Zcount myset 2 4	# 查看2-4之间元素个数
(integer) 3
127.0.0.1:6379> 

其余的很多没有记录到的API可以参考官网文档:

官网:https://redis.io/

中文网:https://www.redis.net.cn/

三种特殊数据类型
geospatial (地理位置)

学习官网:https://www.redis.net.cn/order/3685.html

朋友的定位,附近的人,打车距离计算?我们都可以使用Redis的geo实现,在Redis3.2就有这个版本了。

准备一个可以查询地理城市的经纬度网站:http://www.jsons.cn/lngcode/

六个命令:

添加城市位置

GEOADD

一个坑:

127.0.0.1:6379> GEOADD china:city 39.90 116.40 beijing
(error) ERR invalid longitude,latitude pair 39.900000,116.400000
说明:这种问题是因为将经纬度写反了,必须经度在前纬度在后,英文官网上面写对的但是中文官网写错啦!
127.0.0.1:6379> GEOADD china:city 116.40 39.90 beijing 121.47 31.23 shanghai 106.50 29.53 chongqing 113.28 23.13 guangzhou 114.08 22.54 深圳
(integer) 5
127.0.0.1:6379> 
获取城市坐标值

一定是一个坐标值

GEOPOS

127.0.0.1:6379> GEOPOS china:city beijing chongqing
1) 1) "116.39999896287918091"
   2) "39.90000009167092543"
2) 1) "106.49999767541885376"
   2) "29.52999957900659211"
127.0.0.1:6379> 
查看两个坐标之间的距离

GEODIST

如果两个位置之间的其中一个不存在, 那么命令返回空值。

指定单位的参数 unit 必须是以下单位的其中一个:

  • m 表示单位为米。
  • km 表示单位为千米。
  • mi 表示单位为英里。
  • ft 表示单位为英尺。

如果用户没有显式地指定单位参数, 那么 GEODIST 默认使用米作为单位。

127.0.0.1:6379> GEODIST china:city beijing shanghai km		# 查看北京到上海的直线距离
"1067.3788"
127.0.0.1:6379> GEODIST china:city beijing chongqing km		# 查看北京到重庆的直线距离
"1464.0708"
127.0.0.1:6379> 
以固定的坐标获取某一半径的元素

GEORADIUS

127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km # 查询以坐标110 30(经纬度)半径1000km内的城市
1) "chongqing"
2) "shenzhen"
3) "guangzhou"
127.0.0.1:6379> 

在给定以下可选项时, 命令会返回额外的信息:

  • WITHDIST: 在返回位置元素的同时, 将位置元素与中心之间的距离也一并返回。 距离的单位和用户给定的范围单位保持一致。

    127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km WITHDIST
    1) 1) "chongqing"
       2) "341.9374"
    2) 1) "shenzhen"
       2) "923.9364"
    3) 1) "guangzhou"
       2) "830.7427"
    
  • WITHCOORD: 将位置元素的经度和维度也一并返回。

    127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km WITHDIST WITHCOORD
    1) 1) "chongqing"
       2) "341.9374"
       3) 1) "106.49999767541885376"
          2) "29.52999957900659211"
    2) 1) "shenzhen"
       2) "923.9364"
       3) 1) "114.08000081777572632"
          2) "22.53999903789756587"
    3) 1) "guangzhou"
       2) "830.7427"
       3) 1) "113.27999979257583618"
          2) "23.13000101271457254"
    
  • WITHHASH: 以 52 位有符号整数的形式, 返回位置元素经过原始 geohash 编码的有序集合分值。 这个选项主要用于底层应用或者调试, 实际中的作用并不大。

命令默认返回未排序的位置元素。 通过以下两个参数, 用户可以指定被返回位置元素的排序方式:

  • ASC: 根据中心的位置, 按照从近到远的方式返回位置元素。

    127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km WITHDIST WITHCOORD ASC
    1) 1) "chongqing"
       2) "341.9374"
       3) 1) "106.49999767541885376"
          2) "29.52999957900659211"
    2) 1) "guangzhou"
       2) "830.7427"
       3) 1) "113.27999979257583618"
          2) "23.13000101271457254"
    3) 1) "shenzhen"
       2) "923.9364"
       3) 1) "114.08000081777572632"
          2) "22.53999903789756587"
    
  • DESC: 根据中心的位置, 按照从远到近的方式返回位置元素。

  • COUNT: 限制可以查询出的元素个数。

    127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km WITHDIST WITHCOORD COUNT 1 ASC
    1) 1) "chongqing"
       2) "341.9374"
       3) 1) "106.49999767541885376"
          2) "29.52999957900659211"
    127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km WITHDIST WITHCOORD COUNT 1 DESC
    1) 1) "shenzhen"
       2) "923.9364"
       3) 1) "114.08000081777572632"
          2) "22.53999903789756587"
    127.0.0.1:6379> 
    
以某个元素为中心找出某一半径的坐标

GEORADIUSBYMEMBER

这个命令和GEORADIUS命令一样, 都可以找出位于指定范围内的元素, 但是 GEORADIUSBYMEMBER 的中心点是由给定的位置元素决定的, 而不是像 GEORADIUS那样, 使用输入的经度和纬度来决定中心点。

127.0.0.1:6379> GEORADIUSBYMEMBER china:city beijing 1200 km
1) "beijing"
2) "shanghai"
127.0.0.1:6379> 
返回一个或多个位置元素的 Geohash 表示

通常使用表示位置的元素使用不同的技术,使用Geohash位置52点整数编码。由于编码和解码过程中所使用的初始最小和最大坐标不同,编码的编码也不同于标准。此命令返回一个标准的Geohash

# 将二维的经纬度转换为一维的字符串,如果两个字符串越接近,那么距离就越短。
127.0.0.1:6379> GEOHASH china:city beijing shanghai
1) "wx4fbxxfke0"
2) "wtw3sj5zbj0"
127.0.0.1:6379> 
GEO原理

GEO底层实现其实就是Zset!我们可以使用Zset命令来操作GEO

127.0.0.1:6379> zrem china:city shenzhen	# 移除指定的元素
(integer) 1
127.0.0.1:6379> zrange china:city 0 -1
1) "chongqing"
2) "guangzhou"
3) "shanghai"
4) "beijing"
127.0.0.1:6379> 
HyperLogLog(计数统计)

简介

Redis 2.8.9 版本更新了 HyperLogLog 数据结构。

HyperLogLog是基数统计的一直算法。

优点:占用空间小,固定占用12KB内存,包含2^64不同的元素的基数。从内存的角度考虑HyperLogLog首选。

案例:

统计一个网页的UV(用户访问量:一个人访问一个网址多次只算一次)

传统的方式:使用set保存用户的ID,最后统计元素的个数来计算访问量。这种方式需要保存大量的用户ID,当用户数量很大时,特别的消耗资源。我们的目的是计算访问量,而不是存用户的ID数据。

HyperLogLog官方公布错误率0.81%,对于UV任务来说,可以忽略不计的!

测试HyperLogLog

PFADD:添加元素

PFCOUNT:统计元素个数

PFMERGE:合并两个不同的HyperLogLog生成新的HyperLogLog

127.0.0.1:6379> PFADD mykey a b c d e f g h i j		# 向mykey添加元素
(integer) 1
127.0.0.1:6379> PFCOUNT mykey						# 查看mykey里面元素的个数
(integer) 10
127.0.0.1:6379> PFADD mykey1 i j z x c v b n m		# 向mykey1添加元素
(integer) 1
127.0.0.1:6379> PFCOUNT mykey1						# 查看mykey1里面元素的个数
(integer) 9
127.0.0.1:6379> PFMERGE mykey2 mykey mykey1			# 将mykey和mykey1合并(去重)生成mykey2
OK
127.0.0.1:6379> PFCOUNT mykey2						# 查看mykey2里面元素的个数
(integer) 15
127.0.0.1:6379> 
Bitmaps(位图)

位存储

使用场景:统计用户信息,活跃、不活跃。统计用户是否登录,登录、未登录。打卡,365天打卡。只要是两个状态的都可以使用Bitmaps。

Bitmaps 位图,一直数据结构,操作二进制位来进行记录,非0即1。

测试案例

使用bitmaps 来记录周一到周日的打卡!

周1:1,周2:0,周3:0,周四:1…

setbit:添加元素

127.0.0.1:6379> setbit sign 0 1	# 周1-打卡
(integer) 0
127.0.0.1:6379> setbit sign 1 0	# 周2-未打卡
(integer) 0
127.0.0.1:6379> setbit sign 2 0	# 周3-未打卡
(integer) 0
127.0.0.1:6379> setbit sign 3 1	# 周4-打卡
(integer) 0
127.0.0.1:6379> setbit sign 4 1	# 周5-打卡
(integer) 0
127.0.0.1:6379> setbit sign 5 0	# 周6-未打卡
(integer) 0
127.0.0.1:6379> setbit sign 6 0	# 周天-未打卡
(integer) 0
127.0.0.1:6379> 

getbit:查看元素

查看周四是否打卡

127.0.0.1:6379> getbit sign 3
(integer) 1
127.0.0.1:6379> 

bitcount:统计为1的数量

在一定范围内统计打卡的天数

127.0.0.1:6379> bitcount sign 0 5	# 统计0-5之间打卡数量
(integer) 3
127.0.0.1:6379> bitcount sign		# 默认统计全部
(integer) 3
尾言

本文为狂神说Redis学习笔记

HyperLogLog是基数统计的一直算法。

优点:占用空间小,固定占用12KB内存,包含2^64不同的元素的基数。从内存的角度考虑HyperLogLog首选。

案例:

统计一个网页的UV(用户访问量:一个人访问一个网址多次只算一次)

传统的方式:使用set保存用户的ID,最后统计元素的个数来计算访问量。这种方式需要保存大量的用户ID,当用户数量很大时,特别的消耗资源。我们的目的是计算访问量,而不是存用户的ID数据。

HyperLogLog官方公布错误率0.81%,对于UV任务来说,可以忽略不计的!

测试HyperLogLog

PFADD:添加元素

PFCOUNT:统计元素个数

PFMERGE:合并两个不同的HyperLogLog生成新的HyperLogLog

127.0.0.1:6379> PFADD mykey a b c d e f g h i j		# 向mykey添加元素
(integer) 1
127.0.0.1:6379> PFCOUNT mykey						# 查看mykey里面元素的个数
(integer) 10
127.0.0.1:6379> PFADD mykey1 i j z x c v b n m		# 向mykey1添加元素
(integer) 1
127.0.0.1:6379> PFCOUNT mykey1						# 查看mykey1里面元素的个数
(integer) 9
127.0.0.1:6379> PFMERGE mykey2 mykey mykey1			# 将mykey和mykey1合并(去重)生成mykey2
OK
127.0.0.1:6379> PFCOUNT mykey2						# 查看mykey2里面元素的个数
(integer) 15
127.0.0.1:6379> 
Bitmaps(位图)

位存储

使用场景:统计用户信息,活跃、不活跃。统计用户是否登录,登录、未登录。打卡,365天打卡。只要是两个状态的都可以使用Bitmaps。

Bitmaps 位图,一直数据结构,操作二进制位来进行记录,非0即1。

测试案例

使用bitmaps 来记录周一到周日的打卡!

周1:1,周2:0,周3:0,周四:1…

setbit:添加元素

127.0.0.1:6379> setbit sign 0 1	# 周1-打卡
(integer) 0
127.0.0.1:6379> setbit sign 1 0	# 周2-未打卡
(integer) 0
127.0.0.1:6379> setbit sign 2 0	# 周3-未打卡
(integer) 0
127.0.0.1:6379> setbit sign 3 1	# 周4-打卡
(integer) 0
127.0.0.1:6379> setbit sign 4 1	# 周5-打卡
(integer) 0
127.0.0.1:6379> setbit sign 5 0	# 周6-未打卡
(integer) 0
127.0.0.1:6379> setbit sign 6 0	# 周天-未打卡
(integer) 0
127.0.0.1:6379> 

getbit:查看元素

查看周四是否打卡

127.0.0.1:6379> getbit sign 3
(integer) 1
127.0.0.1:6379> 

bitcount:统计为1的数量

在一定范围内统计打卡的天数

127.0.0.1:6379> bitcount sign 0 5	# 统计0-5之间打卡数量
(integer) 3
127.0.0.1:6379> bitcount sign		# 默认统计全部
(integer) 3
尾言

本文为狂神说Redis学习笔记

学习地址:https://www.bilibili.com/video/BV1S54y1R7SB?p=1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值