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)
我尝试跟踪返回的光标值几次迭代,但没有编写脚本来检查它,看起来似乎是无穷无尽的空结果。
发生什么事了?
我最终决定编码它:
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 (!) 次迭代,其中在某些迭代中恰好找到了一个匹配项,即:
因此,我使用
SCAN
是为了“友善”,这导致了与服务器的 1058 次往返。
我做错了什么吗?
我不认为这是 redis 扫描返回空结果但非零游标的重复。为了获得一些结果而对服务器进行 1K+ 次往返似乎不合理。
KEYS
命令的行为与SCAN
命令完全不同。
KEYS
命令迭代 Redis 中的所有键,并过滤与给定模式匹配的键。这就是为什么单次往返就能给您答案。但是,当运行 KEYS
命令时,Redis 会阻塞,无法处理其他命令。因此,在生产环境中使用 KEYS
命令是一个坏主意,特别是当您拥有大型数据集时。
SCAN
命令还会迭代 Redis 中的键。但是,对于每次扫描,它仅检查几个键(您可以使用 count
参数来控制键的数量),过滤与您的模式匹配的键,然后返回。因此需要进行多次往返来迭代Redis中的所有键。由于每次扫描操作只检查几个键,因此不会长时间阻塞Redis。这是扫描密钥空间的推荐方法。
代码执行了 1058 (!) 次迭代,其中在某些迭代中恰好找到了一个匹配项,即
因为你有一个很大的数据集,并且只有几个键匹配你的模式(一小部分)。前 1057 次扫描未获得与模式匹配的密钥。
所以,我为了“友好”而使用了 SCAN,它导致了 1058 次与服务器的往返。我是不是做错了什么?
是的,
SCAN
比KEYS
更好,特别是当你需要扫描Redis中的所有键时(没有指定模式,或者大部分键与模式匹配)。
但是,对于您的情况,更好的解决方案是为与模式匹配的键创建辅助索引。比如说,您可以将这些密钥保存在 Redis SET 中,然后扫描该 SET 来获取密钥。