O comando KEYS retorna alguns resultados:
> 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"
Mas o SCAN usando o mesmo padrão não retorna nenhum:
> scan 0 match Types/*/*BackgroundJob.json
1) "1966080"
2) (empty list or set)
Tentei seguir o valor do cursor retornado por várias iterações, mas sem um script para verificá-lo, parece uma série interminável de resultados vazios.
O que está acontecendo?
Editar 1
Finalmente decidi codificá-lo:
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);
}
O código executou 1058 (!) iterações onde exatamente uma correspondência foi encontrada em alguma iteração, a saber:
- 173
- 189
- 242
- 351
- 416
- 473
- 590
- 912
- 975
- 983
- 998
- 1027
Então, eu usei SCAN
para ser "legal" e isso causou 1058 viagens de ida e volta para o servidor.
Estou fazendo algo errado?
Possível duplicado
Não acho que isso seja uma duplicata de redis scan returns empty results but nonzero cursor . Não parece razoável fazer mais de 1K round-trips para o servidor para obter apenas alguns resultados.
O
KEYS
comando se comporta de forma totalmente diferente doSCAN
comando.KEYS
command itera todas as chaves no Redis e filtra chaves que correspondem ao seu padrão fornecido. É por isso que uma única viagem de ida e volta fornece a resposta. No entanto, ao executarKEYS
command, o Redis bloqueia e não consegue processar outro command. Portanto, é uma má ideia usarKEYS
command no ambiente de produção, especialmente quando você tem um grande conjunto de dados.SCAN
O comando também itera as chaves no Redis. No entanto, para cada varredura, ele verifica apenas algumas chaves (você pode usar ocount
parâmetro para controlar o número de chaves), filtra as chaves que correspondem ao seu padrão e retorna. Portanto, você precisa fazer várias viagens de ida e volta para iterar todas as chaves no Redis. Como cada operação de varredura verifica apenas algumas chaves, ela não bloqueará o Redis por muito tempo. E essa é a maneira recomendada de escanear o espaço de chaves.Porque você tem um grande conjunto de dados e há apenas algumas chaves que correspondem ao seu padrão (uma pequena proporção). As primeiras 1057 varreduras não obtêm uma chave que corresponda ao padrão.
SIM,
SCAN
é melhor queKEYS
, especialmente quando você precisa escanear todas as chaves no Redis (nenhum padrão especificado ou uma grande parte das chaves corresponde ao padrão).No entanto, no seu caso, uma solução melhor é criar um índice secundário para as chaves que correspondem ao padrão. Digamos que você pode salvar essas chaves em um Redis SET e escanear o SET para obter as chaves.