批量删除Key

重要

本文中含有需要您注意的重要提示信息,忽略该信息可能对您的业务造成影响,请务必仔细阅读。

批量删除指定Key,推荐使用Redis UNLINK命令结合Linuxcatxargs命令。批量模糊删除具有相同前缀或后缀的Key,推荐使用RedisSCANUNLINK命令。

注意事项

  • 建议删除前先备份数据,并在业务低峰期执行删除操作。

  • 下文示例需通过ECS或本地的redis-cli、Python客户端执行相关操作,不支持在DMS中执行。

批量删除指定Key

执行命令前,您需要把待删除的Key列表写入至文件。

通过cat命令从指定文件中读取每一行作为RedisKey,然后使用 redis-cli 连接到 Redis 服务器,并使用UNLINK命令删除这些Key。命令语法如下。

# 使用 UNLINK (Redis 4.0+) 异步删除,避免阻塞。如果版本低于 Redis 4.0,请将 UNLINK 替换成 DEL
cat <file> | xargs redis-cli -h <host> -p <port> -a <password> UNLINK
说明

Linuxxargs命令可以将参数列表分段传递给其他命令,以避免参数列表过长的问题,可以单独使用,也可以使用管道符、重定位符等与其他命令配合使用。

参数说明:

  • file:记录了待删除Key的文件路径。例如key.txt。

  • host:Redis的实例连接地址,更多信息请参见查看连接地址

  • port:Redis的端口号,默认6379。

  • password:Redis实例密码,更多信息请参见实例的登录方式

示例:

cat key.txt | xargs redis-cli -h r-bp127cu5tb*****.redis.rds.aliyuncs.com -a Test**** UNLINK

批量删除模糊匹配Key

方法

适用场景

(推荐)通过SCANUNLINK命令模糊删除

在生产环境中安全地清理大量数据。此方法不会阻塞服务器,能确保线上服务的稳定性 。

通过Pipeline模式高吞吐量模糊删除

在需要极致删除效率的场景下,通过一次性批量提交大量命令来最大化吞吐量并减少网络延迟。

通过KEYSDEL命令模糊删除

开发、测试环境或在业务完全停止时清理少量数据场景。因KEYS命令会阻塞服务器,在生产环境使用风险极高。

(推荐)通过SCANUNLINK命令模糊删除

通过循环逐步遍历并删除符合条件的Key。Python代码示例:

import redis
import sys

def main(argv):
    if len(argv) < 4:
        print("Usage: python scan_and_del.py host port password match")
        sys.exit(-1)

    host = argv[1]
    port = argv[2]
    password = argv[3]
    match = argv[4]
    print("host: %s, port: %s, password: %s, match: %s\n" % (host, port, password, match))

    redis_cli = redis.StrictRedis(host=host, port=port, password=password)
    cursor = 0
    rnd = 1

    while rnd == 1 or cursor != 0:
        result = redis_cli.scan(cursor=cursor, match=match, count=1000)
        ret_cursor = result[0]
        ret_keys = result[1]
        num_keys = len(ret_keys)
        print("del %d keys in round %d, cursor: %d" % (num_keys, rnd, ret_cursor))
        if 0 != num_keys:
            ret_unlink = redis_cli.unlink(*ret_keys)
            print("ret_unlink: %d, ret_keys: %s" % (ret_unlink, ret_keys))
        cursor = ret_cursor
        rnd += 1
        print("")

if __name__ == '__main__':
    main(sys.argv)

调用上述示例代码scan_and_unlink.py,调用时指定Redis实例的连接信息和Key的匹配模式,即可实现模糊匹配删除。

python scan_and_unlink.py <host> <port> <password> "<key>" 

参数说明:

  • host:Redis的实例连接地址,更多信息请参见查看连接地址

  • port:Redis实例的端口号,默认6379。

  • password:Redis实例密码,更多信息请参见实例的登录方式

  • key:某个数据库中符合指定要求的Key,例如"test*"标识以test为前缀的Key,如test1test2test3等。

    关于通配符匹配的更多说明:

    • w?rld:匹配以w开头,以rl结尾,且长度为5个字符的字符串,例如world,warldwxrld等。

    • w*rld:匹配以w开头,以rl结尾的任意字符串,例如wrldwoooorld。

    • w[ae]rld:匹配warldwerld,但是不匹配world等。

    • w[^e]rld:匹配worldwarld等,但是不匹配werld。

    • w[a-b]rld:匹配warldwbrld。

通过Pipeline模式高吞吐量模糊删除

通过循环逐步遍历符合条件的Key,然后将这些Key通过 UNLINK 命令打包在 Pipeline 中一次性发送,从而显著减少网络往返时间(RTT)。Python代码示例:

import redis
import sys


def main(argv):
    if len(argv) < 4:
        print("Usage: python scan_and_del_pipeline.py host port password match")
        sys.exit(-1)

    host = argv[1]
    port = int(argv[2])  # Convert port to integer
    password = argv[3]
    match = argv[4]
    print(f"host: {host}, port: {port}, password: {'*' * len(password)}, match: {match}\n")

    # 每次累积1000个key后,通过Pipeline提交一次DEL命令,可根据业务需求调整
    pipeline_batch_size = 1000
    
    redis_cli = redis.StrictRedis(host=host, port=port, password=password, decode_responses=True)
    
    cursor = 0
    total_deleted_count = 0
    keys_to_delete = []

    print("Starting key scan...")
    # 使用 'while True' 循环,在 cursor 为 0 时退出
    while True:
        # 1. 扫描一批key
        cursor, keys = redis_cli.scan(cursor=cursor, match=match, count=1000)

        if keys:
            # 2. 将扫描到的key收集到待删除列表中
            keys_to_delete.extend(keys)

        # 3. 当待删除列表达到批处理大小,或者扫描已完成时,执行删除
        if len(keys_to_delete) >= pipeline_batch_size or cursor == 0:
            if keys_to_delete:
                print(f"Accumulated {len(keys_to_delete)} keys. Preparing to delete via Pipeline...")

                # --- Pipeline -----------
                pipe = redis_cli.pipeline(transaction=False, shard_hint=None)
                pipe.delete(*keys_to_delete)
                result = pipe.execute()
                # -------------------------

                deleted_in_batch = result[0]
                total_deleted_count += deleted_in_batch

                print(f"  -> Pipeline executed. Deleted {deleted_in_batch} keys in this batch.")

                # 清空待删除列表,为下一批做准备
                keys_to_delete = []

        # 4. 如果扫描完成,则退出循环
        if cursor == 0:
            break

    print(f"\nScan finished. Total keys deleted: {total_deleted_count}")


if __name__ == '__main__':
    main(sys.argv)

调用上述示例代码scan_and_unlink_pipe.py,调用时指定Redis实例的连接信息和Key的匹配模式,即可实现模糊匹配删除。

python scan_and_unlink_pipe.py <host> <port> <password> "<key>" 

参数说明:

  • host:Redis的实例连接地址,更多信息请参见查看连接地址

  • port:Redis实例的端口号,默认6379。

  • password:Redis实例密码,更多信息请参见实例的登录方式

  • key:某个数据库中符合指定要求的Key,例如"test*"标识以test为前缀的Key,如test1test2test3等。

    关于通配符匹配的更多说明:

    • w?rld:匹配以w开头,以rl结尾,且长度为5个字符的字符串,例如world,warldwxrld等。

    • w*rld:匹配以w开头,以rl结尾的任意字符串,例如wrldwoooorld。

    • w[ae]rld:匹配warldwerld,但是不匹配world等。

    • w[^e]rld:匹配worldwarld等,但是不匹配werld。

    • w[a-b]rld:匹配warldwbrld。

通过KEYSDEL命令模糊删除

警告
  • 使用KEYS命令可能会导致CPU使用率高,请在业务低峰期操作。

  • 数据库中数据较多,使用KEYS命令会影响数据库的性能,建议在数据较少时使用。

通过KEYS命令,使用通配符模糊匹配所有符合条件的Key,再通过DEL命令删除这些Key。

redis-cli -h <host> -p <port> -a <password> KEYS "<key>" | xargs redis-cli -h <host> -p <port> -a <password> DEL

参数说明:

  • host:Redis的实例连接地址,更多信息请参见查看连接地址

  • port:Redis实例的端口号,默认6379。

  • password:Redis实例密码,更多信息请参见实例的登录方式

  • key:某个数据库中符合指定要求的Key,例如"test*"标识以test为前缀的Key,如test1test2test3等。

    关于通配符匹配的更多说明:

    • w?rld:匹配以w开头,以rl结尾,且长度为5个字符的字符串,例如world,warldwxrld等。

    • w*rld:匹配以w开头,以rl结尾的任意字符串,例如wrldwoooorld。

    • w[ae]rld:匹配warldwerld,但是不匹配world等。

    • w[^e]rld:匹配worldwarld等,但是不匹配werld。

    • w[a-b]rld:匹配warldwbrld。

示例:

redis-cli -h r-bp127cu5tb*****.redis.rds.aliyuncs.com -a Test**** KEYS "keys*" | xargs redis-cli -h r-bp127cu5tb*****.redis.rds.aliyuncs.com -a Test**** DEL

验证Key是否成功删除

使用 SCAN 再次扫描,确认没有匹配的 Key 返回。

# 统计匹配的 Key 数量,预期为 0
redis-cli -h <host> -p <port>  -a <password> --scan --pattern 'test:*' | wc -l