Estoy trabajando en un gran proyecto y, en algunos lugares, tengo que eliminar claves según un patrón, por ejemplo, quiero eliminar todas las claves que comienzan con filterProducts
Hice una búsqueda en Google y encontré algunos métodos para hacerlo, como, por ejemplo, el método de este artículo.
Pero no sé cuál es la más eficiente para un gran proyecto, ¿podrían ayudarme?
El método al que se vinculó es una forma bastante terrible de hacerlo. KEYS
es válido para la producción y DEL también es bastante ineficiente. Comprobaría el uso de SCAN
y UNLINK
. De esta manera, puede eliminar un puñado de claves a la vez sin inmovilizar Redis.
Dicho todo esto, ese tipo de script depende de usted y está más allá del alcance de la biblioteca cliente. Voy a cerrar el tema.
@ MohammedAl-Mahdawi Tengo un caso de uso similar en uno de mis proyectos y uso la implementación scanStream
ofrecida por ioredis. Esta es básicamente una forma más fácil de usar el comando scan
: https://github.com/luin/ioredis#streamify -scanning
Si usa SCAN
y UNLINK
como @stockholmux ya mencionado, debería poder eliminar cualquier número de claves sin bloquear Redis.
@dirkbonhomme Muchas gracias por su ayuda, se lo agradezco mucho.
Seguí sus consejos, utilicé ioredis y creé las siguientes funciones, ¿podría decirme que para grandes proyectos es la siguiente manera más eficiente de hacerlo o no?
//key example "prefix*"
function getKeysByPattern(key) {
return new Promise((resolve, reject) => {
var stream = redis.scanStream({
// only returns keys following the pattern of "key"
match: key,
// returns approximately 100 elements per call
count: 100
});
var keys = [];
stream.on('data', function (resultKeys) {
// `resultKeys` is an array of strings representing key names
for (var i = 0; i < resultKeys.length; i++) {
keys.push(resultKeys[i]);
}
});
stream.on('end', function () {
resolve(keys)
});
})
}
//key example "prefix*"
function deleteKeysByPattern(key) {
var stream = redis.scanStream({
// only returns keys following the pattern of "key"
match: key,
// returns approximately 100 elements per call
count: 100
});
var keys = [];
stream.on('data', function (resultKeys) {
// `resultKeys` is an array of strings representing key names
for (var i = 0; i < resultKeys.length; i++) {
keys.push(resultKeys[i]);
}
});
stream.on('end', function () {
redis.unlink(keys)
});
}
@ MohammedAl-Mahdawi me parece bien. El único problema posible es que cargará todas las claves coincidentes en la memoria a la vez. Si eso es un problema, puede eliminarlos en lotes tan pronto como entren:
stream.on('data', function (resultKeys) {
if (resultKeys.length) {
redis.unlink(resultKeys);
}
});
@dirkbonhomme y @ MohammedAl-Mahdawi Este método tiene problemas de atomicidad que podrían afectarlo en la producción.
@stockholmux Gracias por su ayuda, entonces, ¿cuál es la solución adecuada a este problema, por favor?
Para cualquiera que busque el resultado final al que hemos llegado hasta ahora y crea que es la forma más eficiente es la siguiente:
//key example "prefix*"
function getKeysByPattern(key) {
return new Promise((resolve, reject) => {
var stream = redis.scanStream({
// only returns keys following the pattern of "key"
match: key,
// returns approximately 100 elements per call
count: 100
});
var keys = [];
stream.on('data', function (resultKeys) {
// `resultKeys` is an array of strings representing key names
for (var i = 0; i < resultKeys.length; i++) {
keys.push(resultKeys[i]);
}
});
stream.on('end', function () {
resolve(keys)
});
})
}
//key example "prefix*"
function deleteKeysByPattern(key) {
var stream = redis.scanStream({
// only returns keys following the pattern of "key"
match: key,
// returns approximately 100 elements per call
count: 100
});
var keys = [];
stream.on('data', function (resultKeys) {
// `resultKeys` is an array of strings representing key names
for (var i = 0; i < resultKeys.length; i++) {
keys.push(resultKeys[i]);
}
});
stream.on('end', function () {
redis.unlink(keys)
});
}
//key example "prefix*"
function batchDeletionKeysByPattern(key) {
var stream = redis.scanStream({
// only returns keys following the pattern of "key"
match: key,
// returns approximately 100 elements per call
count: 100
});
stream.on('data', function (resultKeys) {
if (resultKeys.length) {
redis.unlink(resultKeys);
}
});
}
El código anterior es para ioredis .
Por favor, si usted es alguien que conoce una mejor manera de hacerlo, no dude en compartirlo.
@ MohammedAl-Mahdawi,
Recibo este error alguna idea sobre el mismo
base de código:
let redisDel = () => {
var key="employees*"
return new Promise((resolve, reject) => {
var stream = redis.scanStream({
// only returns keys following the pattern of "key"
match: key,
// returns approximately 100 elements per call
count: 100
});
stream.on('data', function (resultKeys) {
if (resultKeys.length) {
console.log(resultKeys)
redis.unlink(resultKeys);
}
});
stream.on('end', function (resultKeys) {
resolve()
})
})
}
¿Alguien da la solución perfecta aquí?
@ siddhkadam1881 El comando de desvinculación solo está disponible desde Redis 4 https://redis.io/commands/unlink
Probablemente esté ejecutando una versión anterior. Pruebe del
lugar.
Quiero entender como se hace el escaneo ?. Creo que en la solución de @ MohammedAl-Mahdawi, si la eliminación ocurre en lotes, ¿existe la posibilidad de que las nuevas claves agregadas en ese momento que no deseamos eliminar, sean escaneadas y eliminadas? ¿Qué tal un guión lua?
Alguien tiene alguna idea de por qué esta solución no funcionaría en un servidor ElastiCache de 1 instancia muy simple, pero ¿funciona localmente? Puedo borrar las claves normalmente, pero si trato de usar la implementación de la transmisión, nunca devuelve ninguna clave en ElastiCache.
Comentario más útil
Para cualquiera que busque el resultado final al que hemos llegado hasta ahora y crea que es la forma más eficiente es la siguiente:
El código anterior es para ioredis .
Por favor, si usted es alguien que conoce una mejor manera de hacerlo, no dude en compartirlo.