当前位置: 首页 > news >正文

Redis KEY*模糊查询导致速度慢、阻塞其他 Redis 操作

Redis KEY*模糊查询导致交互速度慢、阻塞其他 Redis 操作

在这里插入图片描述

查询速度慢的原因

在Redis中,使用通配符 KEYS 命令进行键的模糊匹配(比如 KEYS key*)可能会导致性能问题,尤其是在数据集较大时。这是因为 KEYS 命令的实现需要遍历所有的键来匹配模式,这个过程的时间复杂度是 O(N),其中 N 是键的总数,因此使用KEYS*命令查询时,Redis的响应速度和Redis中数据量成正比

在大规模的生产环境中,遍历所有键可能会导致阻塞其他 Redis 操作,因为 KEYS 命令会持有数据库的写锁。此外,这也可能对性能产生负面影响,因为它需要消耗大量的计算资源。在 Redis 中,所有命令都是按顺序执行的,一个命令执行完成后,才会执行下一个命令。这个单线程模型是 Redis 的设计选择之一,有助于简化并发控制,提高数据一致性。

使用带前缀的通配符 KEYS prefix*

在 Redis 中,使用带前缀的通配符 KEYS prefix* 仍然需要遍历所有匹配前缀的键。虽然带有前缀的通配符能够减小匹配的范围,但是在 Redis 中并没有内置的索引结构能够直接加速带有通配符的键的查找。

这是因为Redis 的键是以哈希表的形式存储的,通过哈希函数计算出键的位置。当使用通配符 KEYS prefix* 时,Redis 无法直接利用哈希函数来快速定位符合条件的键,而需要遍历哈希表中的所有键,然后筛选匹配的键。

如果对于特定的使用场景,你经常需要根据键的前缀来查询数据,可以考虑使用 Redis 的有序集合(Sorted Set)来模拟带有前缀的键的查询。在有序集合中,你可以将键的前缀作为分数,然后使用范围查询来获取符合条件的键。这样可以更有效地执行带有前缀的查询,但这需要根据具体情况来设计和维护有序集合。

总体来说,避免在生产环境中使用 KEYS 命令,尤其是在大规模数据集上,因为它可能导致性能问题。在生产环境中,当出现使用KEYS*的场景时,一定要谨慎,考虑如何改变reid key的数据结构来避免使用;如果非要遍历所有keys不可,更推荐使用迭代命令(如 SCAN)以及结合合适的数据结构来执行查询,它可以用于迭代集合中的元素而不会阻塞整个数据库,特别是在大型数据库中,因为它将迭代的工作分散到多个步骤,并允许客户端逐步处理结果。这样可以避免 KEYS 命令可能引起的性能问题。

特殊场景SCAN 一个用于迭代集合元素的命令

SCAN 是 Redis 提供的一个用于迭代集合元素的命令。它可以用于逐步迭代集合中的元素,而不会一次性获取所有元素。这样可以减小对 Redis 服务器的负载,并且不会阻塞其他的 Redis 命令。

SCAN 命令的一般用法是:

SCAN cursor [MATCH pattern] [COUNT count]

其中:

  • cursor 是一个用于标识迭代状态的整数,初始时通常设置为 0。
  • MATCH pattern 是一个可选参数,用于匹配指定的模式。
  • COUNT count 是一个可选参数,用于指定每次迭代返回的元素数量。

SCAN 命令会返回一个包含两个元素的数组,第一个元素是下一次迭代所需的新的 cursor,第二个元素是包含元素的数组。

例子:

SCAN 0 COUNT 10

这个命令将从集合的开头开始迭代,每次返回最多 10 个元素。

使用 SCAN 命令相比于 KEYS 命令,主要优势在于它不会阻塞 Redis 服务器太长时间,因为它可以分阶段地获取数据。KEYS 命令可能会导致阻塞,因为它要在一次性操作中返回所有匹配的键。

需要注意的是,由于 SCAN 是迭代器,返回的结果可能不是实时的快照,而是在迭代开始时的一个快照。因此,在迭代过程中,集合的内容可能会发生变化。


使用 SCAN 命令时,通常需要在程序中进行多次调用直到迭代结束。每次调用 SCAN 命令都会返回下一批符合条件的元素和新的游标值,程序需要根据新的游标值决定是否继续迭代。

基本的流程如下:

  1. 使用 SCAN 0 命令开始迭代,初始游标设置为 0。
  2. 处理 SCAN 命令返回的结果,包括下一批元素和新的游标值。
  3. 如果新的游标值为 0,表示迭代结束;否则,使用新的游标值再次调用 SCAN 命令,重复步骤 2。
  4. 继续处理迭代结果,直到迭代结束。

这样的迭代方式可以确保不会对 Redis 服务器造成较大的负载,同时适应大型数据集的处理。

示例(伪代码):

cursor = 0while True:result = redis_client.scan(cursor, count=10)elements = result[1]# 处理当前批次的元素cursor = result[0]if cursor == 0:break

这样的迭代方式可以有效地处理大型数据集,减小对 Redis 服务器的压力。

相关文章:

  • 破晓6G新时代:迈向新一代星地融合的高速测试解决方案
  • Mysql的多表联合查询
  • OpenAI 承认 ChatGPT 最近确实变懒,承诺修复问题
  • 基于Maven构建OSGI应用(Maven和OSGI结合)
  • 为什么现在是学习 Rust 的最佳时机
  • js根据数组对象中的某个值去重
  • Android audio设置投屏和喇叭双输出
  • 【数据结构和算法】--队列
  • Kubernetes(k8s)集群部署----->超详细
  • Spring Boot学习随笔- 集成JSP模板(配置视图解析器)、整合Mybatis(@MapperScan注解的使用)
  • 企业选CRM系统,这3个关键点你一定不能错过
  • 【摸鱼向】利用Arduino实现自动化切屏
  • python自动化测试实战 —— 自动化测试框架的实例
  • MySQL 报错 You can‘t specify target table for update in FROM clause解决办法
  • Flink 读写 HBase 总结
  • .pyc 想到的一些问题
  • 《深入 React 技术栈》
  • 【Linux系统编程】快速查找errno错误码信息
  • es的写入过程
  • js递归,无限分级树形折叠菜单
  • Redis 中的布隆过滤器
  • weex踩坑之旅第一弹 ~ 搭建具有入口文件的weex脚手架
  • 分享一份非常强势的Android面试题
  • 前嗅ForeSpider教程:创建模板
  • 小而合理的前端理论:rscss和rsjs
  • elasticsearch-head插件安装
  • 阿里云服务器如何修改远程端口?
  • ​ArcGIS Pro 如何批量删除字段
  • ​LeetCode解法汇总1276. 不浪费原料的汉堡制作方案
  • (01)ORB-SLAM2源码无死角解析-(56) 闭环线程→计算Sim3:理论推导(1)求解s,t
  • (附表设计)不是我吹!超级全面的权限系统设计方案面世了
  • (附源码)ssm基于web技术的医务志愿者管理系统 毕业设计 100910
  • (附源码)小程序儿童艺术培训机构教育管理小程序 毕业设计 201740
  • (三)docker:Dockerfile构建容器运行jar包
  • (太强大了) - Linux 性能监控、测试、优化工具
  • (五)关系数据库标准语言SQL
  • .Net 8.0 新的变化
  • .net on S60 ---- Net60 1.1发布 支持VS2008以及新的特性
  • .NET 使用 ILRepack 合并多个程序集(替代 ILMerge),避免引入额外的依赖
  • .NET 中使用 TaskCompletionSource 作为线程同步互斥或异步操作的事件
  • .Net(C#)常用转换byte转uint32、byte转float等
  • .net遍历html中全部的中文,ASP.NET中遍历页面的所有button控件
  • []C/C++读取串口接收到的数据程序
  • [Angular 基础] - 自定义指令,深入学习 directive
  • [Angular] 笔记 9:list/detail 页面以及@Output
  • [C++]C++基础知识概述
  • [CSS]中子元素在父元素中居中
  • [Effective C++读书笔记]0012_复制对象时勿忘其每一部分
  • [EFI]Dell Latitude-7400电脑 Hackintosh 黑苹果efi引导文件
  • [Firefly-Linux] RK3568 pca9555芯片驱动详解
  • [Flutter]设置应用包名、名称、版本号、最低支持版本、Icon、启动页以及环境判断、平台判断和打包
  • [Intel Edison开发板] 05、Edison开发基于MRAA实现IO控制,特别是UART通信
  • [IOI2007 D1T1]Miners 矿工配餐
  • [Java开发之路](14)反射机制
  • [LeetCode][面试算法]逻辑闭环的二分查找代码思路