You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

面向多企业应用的Redis键管理优化及高效删键方案问询

问题

我正在为服务数百家企业的应用搭建Redis,拟采用如下键结构:

companyname1:xxx:yyy:zzz
companyname1:yyy
companyname1:qqq:zz:xxx:ppp
companyname1:tttt:zz:qqq
companyName1:iiii:rrrr
companyName1:ppp:ddd:xxx
[... thousands more]

每家企业的键遵循类似模式。我需要删除仅属于companyname1且键中任意位置包含"xxx"的所有键,希望避免Redis全库搜索,请问如何对各企业的键进行分组并仅针对该分组操作?

我使用StackExchange实现了如下代码,但不确定其有效性及效率:

var keysToDelete = new List<RedisKey>();
var cursor = 0L;
var pageSize = 100; 

// pattern = "companyName1::xxx:";
do
{
    var redisResult = await _database.ExecuteAsync("SCAN", cursor.ToString(), "MATCH", pattern, "COUNT", pageSize).ConfigureAwait(false);
    var result = (RedisResult[])redisResult;

    cursor = Convert.ToInt64((string)result[0]);
    keysToDelete.AddRange((RedisKey[])result[1]);
}
while (cursor != 0);
专业指导

一、当前代码的核心问题

你写的pattern = "companyName1::xxx:"存在两个明显错误:

  1. 键的分隔符是单个冒号,但你的pattern用了两个冒号,会漏掉所有中间只有单个冒号的键;
  2. 该pattern只能匹配xxx紧跟在companyName1::之后的键,无法匹配xxx在键中任意位置的场景。

二、正确的分组与过滤思路

你的键设计本身已经通过companyname1:前缀实现了企业分组,不需要额外的分组结构。要避免全库搜索,只需用精准的SCAN匹配模式,让Redis在服务器端直接过滤出目标键,而非全库扫描后在客户端过滤。

三、优化后的代码实现

直接使用StackExchange.Redis封装好的ScanAsync方法(比手动调用ExecuteAsync更简洁可靠),同时修正匹配模式、优化执行效率:

var keysToDelete = new List<RedisKey>();
long cursor = 0;
// 注意Redis键大小写敏感,若需匹配companyname1和companyName1需调整模式
var scanOptions = new ScanOptions
{
    // 匹配以companyname1开头、任意位置包含xxx的键
    Match = "companyname1:*xxx*",
    // 调大COUNT值减少SCAN轮次,提升效率(COUNT是提示值,非精确返回数量)
    Count = 1000
};

do
{
    var scanResult = await _database.ScanAsync(cursor, scanOptions).ConfigureAwait(false);
    cursor = scanResult.Cursor;
    keysToDelete.AddRange(scanResult.Items);
} while (cursor != 0);

// 分批删除,避免一次性删除大量键阻塞Redis
const int deleteBatchSize = 1000;
for (int i = 0; i < keysToDelete.Count; i += deleteBatchSize)
{
    var batchKeys = keysToDelete.Skip(i).Take(deleteBatchSize).ToArray();
    await _database.KeyDeleteAsync(batchKeys).ConfigureAwait(false);
}

四、关键优化点说明

  1. 匹配模式修正:companyname1:*xxx*是正确的模式,其中*是Redis通配符,代表任意长度的字符(包括空),能精准覆盖所有以companyname1:开头且包含xxx的键。
  2. COUNT参数调优:默认100的COUNT会增加SCAN的轮次,调至1000~5000可减少网络往返次数,提升扫描效率(Redis会根据当前数据集大小调整实际返回数量,COUNT仅为提示)。
  3. 分批删除:若目标键数量过万,一次性调用KeyDeleteAsync会阻塞Redis主线程,分批删除能将性能影响降到最低。
  4. 大小写敏感问题:Redis键是大小写敏感的,你的示例中同时存在companyname1和companyName1,若需同时匹配两种前缀,可使用[cC]ompany[nN]ame1:*xxx*模式,或统一键的命名规范(推荐统一小写,避免后续混乱)。

五、额外注意事项

  • 尽量在业务低峰期执行删除操作,即使是渐进式SCAN和分批删除,仍会占用Redis资源;
  • 若数据集极大(百万级以上键),可考虑使用Lua脚本在Redis服务器端完成扫描+删除,进一步减少网络传输开销,但需控制脚本执行时长(避免超过100ms);
  • 后续维护时,可将企业前缀作为固定规范,所有针对单个企业的操作都通过前缀+通配符的方式过滤,避免全库操作。

内容的提问来源于stack exchange,提问作者Tomasz Cioch

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 21:36:09