ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
>[info] set 数据类型与结构 **set类型介绍:** redis集合(set)类型和list列表类型类似,都可以用来存储多个字符串元素的集合。但是和list不同的是set集 合当中不允许重复的元素。而且set集合当中元素是没有顺序的,不存在元素下标。 ***** redis的set类型是使用哈希表构造的,因此复杂度是O(1),它支持集合内的增删改查,并且支持多个集合间 的交集、并集、差集操作。可以利用这些集合操作,解决程序开发过程当中很多数据集合间的问题。 ***** **set 数据类型的实现:** Set数据类型的内部编码有两种: 1. Intset(整数集合):当集合元素个数小于set-max-ziplist-entries配置(默认512个),redis会使用intset作为集合的内部实现来减少内存的使用 2. Hashtable(哈希表):当集合类型无法满足intset的条件时,redis会使用hashtable作为集合的内部实现 ***** **交集、差集、并集:** ![](https://img.kancloud.cn/22/89/22892fa93e5f7c6e06d4e3b908aad9b1_866x449.png) ***** **Sadd命令:** 将一个或者多个元素假如到集合当中,假如假如的元素已经存在在集合当中,则不会添加。假如 key不存在,则直接参加一个key,并加入元素。 ``` 127.0.0.1:6379> sadd dbset mysql oracle redis (integer) 3 127.0.0.1:6379> ``` ![](https://img.kancloud.cn/36/c7/36c78282d2303399157730497370d993_450x79.png) ***** **Smembers 命令:** 将返回集合中的所有的成员。 ``` 127.0.0.1:6379> smembers dbset 1) "oracle" 2) "mysql" 3) "redis" 127.0.0.1:6379> ``` ![](https://img.kancloud.cn/b2/cd/b2cdeed457bfb19780a1b0981b84e917_312x92.png) ***** **Scard 命令:** 返回集合中元素的个数。 ``` 127.0.0.1:6379> scard dbset (integer) 3 127.0.0.1:6379> ``` ![](https://img.kancloud.cn/39/ff/39ff513f3b60b4ffef288342931f6605_258x63.png) ***** **Sismember(查询) 命令:** 判断指定的值是否是集合的成员,假如不是集合的成员,或 key 不存在,返回 0 。 ``` 127.0.0.1:6379> sismember dbset oracle (integer) 1 127.0.0.1:6379> sismember dbset test (integer) 0 127.0.0.1:6379> ``` ![](https://img.kancloud.cn/2d/9b/2d9b20ae4f24b99ccea440e42b83af9c_355x100.png) ***** **Srem(移除)命令:** 用于移除集合元素中一个或者多个元素,假如要移除的元素不存在,默认不处理。 ``` 127.0.0.1:6379> srem dbset oracle (integer) 1 127.0.0.1:6379> smembers dbset 1) "mysql" 2) "redis" 127.0.0.1:6379> ``` ***** **Sinter(交集) 命令:** 返回给定所有给定集合的交集。 不存在的集合 key 被视为空集。 当给定集合当中有一个空集 时,结果也为空集。(返回两个集合交集) ``` 127.0.0.1:6379> sadd dbset1 mysql redis memcache orcle (integer) 4 127.0.0.1:6379> sinter dbset dbset1 1) "mysql" 2) "redis" 127.0.0.1:6379> ``` ***** **. sdiff(差集)命令:** 同理,返回指定集合之间的差集。 ``` 127.0.0.1:6379> sadd dbset sqlserver (integer) 1 127.0.0.1:6379> sdiff dbset dbset1 1) "sqlserver" 127.0.0.1:6379> ``` ***** **Sunion(并集) 命令:** 返回给定集合的并集。同理,不存在的集合 key 被视为空集。 ``` 127.0.0.1:6379> sunion dbaset dbset1 1) "memcache" 2) "mysql" 3) "redis" 4) "orcle" 127.0.0.1:6379> ``` ***** **Sscan 命令:** 用于迭代集合中元素,取出匹配条件的元素 ``` 127.0.0.1:6379> sscan dbset 0 match my* 1) "0" 2) 1) "mysql" 127.0.0.1:6379> ``` ***** >[info] redis 慢查询(针对第3步:命令执行时间) 许多存储系统(例如MySQL)提供慢查询日志帮助开发和运维人员定位系统存在的慢操作。**所谓慢查询日 志就是系统在命令执行前后计算每条命令的执行时间,当超过预设阈值**,就将这条命令的相关信息 (例如:发生时间、耗时、命令的详细信息)记录下来,Redis也提供了类似的功能。 ***** **Redis命令的执行过程:** ![](https://img.kancloud.cn/83/1b/831b56129a4c1e359188c4c173ff589b_1497x716.png) ***** **慢查询日志的参数:** **slowlog-log-slower-than:** 指定执行时间超过多少微秒(1秒等于1000000微秒) 的命令请求会被记录到日志上。 ``` 举个例子,如果这个选项值为100,那么执行时间超过100微秒的命令就会被记录到慢查询日志;如 果这个选项值为500,那么执行时间超过500微秒的命令就会被记录到慢查询日志。 ``` **slowlog-max-len:** 指定服务器最多保存多少条慢查询操作,服务器先进先出的方式保存多条慢查询日志, 当服务器存储的慢查询数量等于slowlog-log-len选项值时,服务器在添加一条新的慢查询日志之前,会先将 对旧的一条慢日志先删除。 ``` 举个例子,如果服务器slowlog-log-len的值为100,并且假设服务器已经存储了100条慢查询日志, 那么如果服务器打算添加一条新的慢查询日志的话,他就必须先删除目前保存的最旧的那条日志, 然后在添加新日志。 ``` ***** **实际现象如下:** 先使用config set命令将slow-log-slower-than参数的设置为0微秒,这样redis服务器执行的任何 命令都会记录到慢查询日志中。 接着把slowlog-max-len 参数的值设置的5,让服务器最多只保存5条慢查询记录 ``` 127.0.0.1:6379> config set slowlog-log-slower-than 0 OK 127.0.0.1:6379> config set slowlog-max-len 5 OK 127.0.0.1:6379> slowlog get ``` ***** 下面我们使用redis客户端发送几个请求: ``` 127.0.0.1:6379> set msg "hello world" OK 127.0.0.1:6379> set number 10086 OK 127.0.0.1:6379> set database "Redis" OK 127.0.0.1:6379> set sql mysql OK 127.0.0.1:6379> set nosql memcache OK ``` ***** 然后使用slowlog get来查看服务器所保存的慢查询日志: ``` 127.0.0.1:6379> slowlog get ``` ***** **慢查询日志的保存:** ![](https://img.kancloud.cn/87/d0/87d0ae54a51870dec04d2a360cdfa4fa_1689x663.png) ***** 服务器状态中包含了几个慢查询日志功能有关的属性: ``` struct redisServer { //... // 下一个慢查询日志的ID long long slowlog_entry_id; // 保存了所有查询日志的链表 list *slowlog; // 服务器配置slowlog-log-slower-than选项的值 long long slowlog_log_slower_than; // 服务器配置slowlog-max-len的值 unsigned long slowlog_max_len; } ``` slowlog_entry_id属性的初始值为0,每当创建一天新的慢查询日志时,这个属性值就会作用到新日志的id 值,之后程序会对这个属性的值增一。 ***** >[info] pipeline(管道) 我们知道redis的客户端和服务器之间是通过TCP协议连接的,不论是客户端向redis发送命令还是客户端接收 redis的执行结果,都需要网络通信,都需要一定时间,由于网络性能的不同往返时间也不同,大致的来说 这个时间相当于redis处理一条简单命令(比如插入一个值到链表)的时间。如果我们执行较多的命令,一 来一回,这个往返时间累加起来还是对性能有一定影响的。 ***** 由于redis是单线程,所以在执行多个命令时,都需要等待上一条命令执行完,才能执行下一条命令。因 此,redis底层通信协议提供了对管道技术的支持。通过管道可以一次性发送多条命令并在执行完后一次性 将结果返回,当一组命令中每条命令都不依赖于之前命令的执行结果时就可以将这组命令一起通过管道发 出。管道通过减少客户端与Redis的通信次数来实现降低往返时延累计值的目的 ***** **不使用管道:** redis 是单线程,每次发送1条,会造成各种性能问题。 ![](https://img.kancloud.cn/c9/ea/c9ead75b25e267bf16a386a0ed88ea70_1066x610.png) ***** ~~~ <?php $stime=microtime(true); //获取程序开始执行的时间 echo '开始内存:'.memory_get_usage(), ''; echo PHP_EOL; $redis = new \Redis(); $redis->connect('192.168.29.108',6379); $redis->auth("root"); $t1 = time(); for($i= 0; $iset("key::$i",str_pad($i,4,'0',0)); $redis->get("key::$i"); } $etime=microtime(true);//获取程序执行结束的时间 $total=($etime-$stime); //计算差值 echo "[页面执行时间:{$total} ]s"; echo PHP_EOL; echo '运行后内存:'.memory_get_usage(), ''; echo PHP_EOL; ?> ~~~ ***** **使用管道:** 一次性将一组命令发送给redis,一次性返回结果。 缺点:不具备原子性,内存消耗大。 ![](https://img.kancloud.cn/1c/c1/1cc11015f62ca72ad4ded03babd1f2f1_1632x640.png) ***** ``` <?php $stime=microtime(true); //获取程序开始执行的时间 echo '开始内存:'.memory_get_usage(), ''; echo PHP_EOL; $redis = new \Redis(); $redis->connect('192.168.29.108',6379); $redis->auth("root"); //$pipe=$redis->multi($redis::PIPELINE);//将多个操作当成一个事务执行 $pipe=$redis->pipeline();//(多条)执行命令简单的,更加快速的发送给服务器,但是没有任何原子 性的保证 for($i= 0; $i<10000 ; $i++) { $pipe->set("key::$i",str\_pad($i,4,'0',0)); $pipe->get("key::$i"); } $replies=$pipe->exec(); $etime=microtime(true);//获取程序执行结束的时间 $total=($etime-$stime); //计算差值 echo "[页面执行时间:{$total} ]s"; echo PHP_EOL; echo '运行后内存:'.memory_get_usage(), ''; echo PHP_EOL; ?> ``` *****