为什么当 KEYS 使用相同的模式返回某些内容时,Redis SCAN 会返回空结果?

问题描述 投票:0回答:1

KEYS 命令返回一些结果:

> keys Types/*/*BackgroundJob.json
1) "Types/Xyz.Data/Xyz.Data.BackgroundJobEngine.BackgroundJob.json"
2) "Types/Xyz.Web.SystemAdmin/Xyz.Web.SystemAdmin.Models.Encryption.EncryptionMethodByBackgroundJob.json"
3) "Types/BackgroundJobs/SharpTop.Engine.BackgroundJobs.AutofillBackgroundJob.json"
4) "Types/Quartz.Server/BJE.UDT.BackgroundJob.json"
5) "Types/DFControllersTest.Compensation/DFControllersTest.Compensation.SubmitCompensationPublishBackgroundJob.json"
6) "Types/SpecFlowTest.Architecture.Base/SpecFlowTest.Architecture.Base.Model.IntStudioConfigBackgroundJob.json"
7) "Types/SpecFlowTest.Benefits.UI/SpecFlowTest.Benefits.UI.Base.Services.BackgroundJobsService+BackgroundJob.json"
8) "Types/Xyz.WFM.ExpressionService.Client/Xyz.WFM.ExpressionService.Client.BackgroundJob.ExpressionManagerBackgroundJob.json"
9) "Types/DFControllersTest.Compensation/DFControllersTest.Compensation.SubmitGenerateBudgetWorksheetBackgroundJob.json"
10) "Types/DFControllersTest.Compensation/DFControllersTest.Compensation.SubmitCompensationUnPublishBackgroundJob.json"
11) "Types/IntegrationStudio/IntegrationStudio.DAL.Entities.IntStudioConfigBackgroundJob.json"
12) "Types/IntegrationStudio/IntegrationStudio.DAL.Entities.BackgroundJob.json"

但是使用相同模式的 SCAN 没有返回任何结果:

> scan 0 match Types/*/*BackgroundJob.json
1) "1966080"
2) (empty list or set)

我尝试跟踪返回的光标值几次迭代,但没有编写脚本来检查它,看起来似乎是无穷无尽的空结果。

发生什么事了?

编辑1

我最终决定编码它:

private async IAsyncEnumerable<string> QueryRedisAsync(string pattern, [EnumeratorCancellation] CancellationToken ct = default)
{
    var db = connection.GetDatabase();
    var cursor = "0";
    int count = 0;
    do
    {
        ++count;
        ct.ThrowIfCancellationRequested();

        var tmp = await db.ExecuteAsync("SCAN", cursor, "MATCH", pattern, "COUNT", "1000");
        var scanResult = (RedisResult[])tmp;
        cursor = scanResult[0].ToString();
        var keys = (RedisKey[])scanResult[1];

        foreach (var key in keys)
        {
            yield return key.ToString();
        }
    } 
    while (cursor != "0");
    Console.WriteLine(count);
}

代码执行了 1058 (!) 次迭代,其中在某些迭代中恰好找到了一个匹配项,即:

  1. 173
  2. 189
  3. 242
  4. 351
  5. 416
  6. 473
  7. 590
  8. 912
  9. 975
  10. 983
  11. 998
  12. 1027

因此,我使用

SCAN
是为了“友善”,这导致了与服务器的 1058 次往返。

我做错了什么吗?

可能重复

我不认为这是 redis 扫描返回空结果但非零游标的重复。为了获得一些结果而对服务器进行 1K+ 次往返似乎不合理。

redis
1个回答
0
投票

KEYS
命令的行为与
SCAN
命令完全不同。

KEYS
命令迭代 Redis 中的所有键,并过滤与给定模式匹配的键。这就是为什么单次往返就能给您答案。但是,当运行
KEYS
命令时,Redis 会阻塞,无法处理其他命令。因此,在生产环境中使用
KEYS
命令是一个坏主意,特别是当您拥有大型数据集时。

SCAN
命令还会迭代 Redis 中的键。但是,对于每次扫描,它仅检查几个键(您可以使用
count
参数来控制键的数量),过滤与您的模式匹配的键,然后返回。因此需要进行多次往返来迭代Redis中的所有键。由于每次扫描操作只检查几个键,因此不会长时间阻塞Redis。这是扫描密钥空间的推荐方法。

代码执行了 1058 (!) 次迭代,其中在某些迭代中恰好找到了一个匹配项,即

因为你有一个很大的数据集,并且只有几个键匹配你的模式(一小部分)。前 1057 次扫描未获得与模式匹配的密钥。

所以,我为了“友好”而使用了 SCAN,它导致了 1058 次与服务器的往返。我是不是做错了什么?

是的,

SCAN
KEYS
更好,特别是当你需要扫描Redis中的所有键时(没有指定模式,或者大部分键与模式匹配)。

但是,对于您的情况,更好的解决方案是为与模式匹配的键创建辅助索引。比如说,您可以将这些密钥保存在 Redis SET 中,然后扫描该 SET 来获取密钥。

© www.soinside.com 2019 - 2024. All rights reserved.