Strings, Hashes, Lists, Sets e Sorted Sets no Redis

1. Redis como Banco de Dados NoSQL: Visão Geral dos Tipos de Dados

1.1. Diferenças fundamentais entre modelo relacional (SQL) e modelo chave-valor do Redis

O Redis é um banco de dados NoSQL do tipo chave-valor, que opera inteiramente em memória principal. Diferentemente do modelo relacional SQL, onde os dados são organizados em tabelas com esquemas rígidos, linhas e colunas, o Redis armazena dados como pares chave-valor, onde cada chave é única e o valor pode ser um de seus tipos de dados nativos: String, Hash, List, Set, Sorted Set, entre outros.

Enquanto no SQL você escreveria:

SELECT nome, email FROM usuarios WHERE id = 123;

No Redis, você acessa diretamente pela chave:

GET usuario:123

1.2. Por que Redis não substitui SQL: cenários de uso complementares

O Redis não substitui bancos SQL porque não oferece:
- Consultas ad-hoc complexas com joins
- Garantias ACID completas (embora tenha atomicidade por comando)
- Suporte nativo a schemas relacionais

Os cenários ideais para Redis incluem:
- Cache de consultas SQL: armazenar resultados de queries frequentes
- Gerenciamento de sessões: dados temporários de usuários logados
- Filas de mensagens: processamento assíncrono de tarefas
- Leaderboards e rankings: ordenação em tempo real com Sorted Sets

1.3. Comandos básicos de gerenciamento

SET chave "valor"              # Armazena string
GET chave                      # Recupera valor
DEL chave                      # Remove chave
EXISTS chave                   # Verifica existência (1 ou 0)
TYPE chave                     # Retorna tipo do valor (string, hash, list, etc.)

2. Strings: O Tipo de Dado Mais Simples e Versátil

2.1. Operações básicas

SET nome "Maria Silva"
GET nome                       # "Maria Silva"

MSET cidade "São Paulo" estado "SP"
MGET cidade estado             # ["São Paulo", "SP"]

GETSET nome "João Santos"      # Retorna "Maria Silva" e atualiza para "João Santos"

2.2. Contadores e operações atômicas

SET visitas 0
INCR visitas                   # 1
INCR visitas                   # 2
INCRBY visitas 10              # 12
DECR visitas                   # 11
DECRBY visitas 5               # 6

Essas operações são atômicas, evitando condições de corrida em ambientes concorrentes.

2.3. Strings como cache de consultas SQL

# Simulando cache de uma consulta SQL
SET cache:usuario:42 '{"id":42,"nome":"Ana","email":"ana@email.com"}' EX 3600
GET cache:usuario:42

O parâmetro EX 3600 define TTL (time-to-live) de 1 hora, expirando automaticamente o cache.

3. Hashes: Modelando Objetos e Registros como no SQL

3.1. Estrutura de campo-valor dentro de uma chave

Hashes permitem armazenar múltiplos pares campo-valor sob uma única chave, similar a uma linha de tabela SQL:

HSET usuario:1 nome "Carlos" email "carlos@email.com" idade 30
HGET usuario:1 nome            # "Carlos"
HGETALL usuario:1              # Lista todos campos e valores
HDEL usuario:1 idade           # Remove campo específico

3.2. Comparação com linhas de tabelas SQL

SQL Redis
INSERT INTO usuarios (id, nome, email) VALUES (1, 'Carlos', 'carlos@email.com') HSET usuario:1 nome "Carlos" email "carlos@email.com"
SELECT nome FROM usuarios WHERE id = 1 HGET usuario:1 nome
SELECT * FROM usuarios WHERE id = 1 HGETALL usuario:1
DELETE FROM usuarios WHERE id = 1 DEL usuario:1

3.3. Operações em lote e contadores

HMSET usuario:2 nome "Beatriz" cargo "Analista" salario 5000
HMGET usuario:2 nome cargo     # ["Beatriz", "Analista"]

HINCRBY usuario:2 salario 500  # Incrementa salário para 5500
HKEYS usuario:2                # ["nome", "cargo", "salario"]
HVALS usuario:2                # ["Beatriz", "Analista", "5500"]

4. Lists: Filas, Pilhas e Mensageria Simples

4.1. Operações de inserção e remoção

LPUSH tarefas "relatório"      # Adiciona à esquerda
RPUSH tarefas "reunião"        # Adiciona à direita
RPUSH tarefas "código"

LRANGE tarefas 0 -1            # ["relatório", "reunião", "código"]

LPOP tarefas                   # Remove e retorna "relatório" (esquerda)
RPOP tarefas                   # Remove e retorna "código" (direita)

4.2. Uso como fila (FIFO) e pilha (LIFO)

Fila (FIFO): LPUSH + BRPOP (bloqueante)

# Produtor
LPUSH fila_pedidos "pedido:1001"
LPUSH fila_pedidos "pedido:1002"

# Consumidor (bloqueia até receber item ou timeout)
BRPOP fila_pedidos 0           # ["fila_pedidos", "pedido:1001"]

Pilha (LIFO): LPUSH + LPOP

LPUSH pilha_acoes "ação1"
LPUSH pilha_acoes "ação2"
LPOP pilha_acoes               # Retorna "ação2" (último inserido)

4.3. Listas como substitutas de tabelas de log

# Armazenar últimas ações do usuário (limitado a 100)
LPUSH log:usuario:42 "login:2024-01-15 10:30"
LTRIM log:usuario:42 0 99      # Mantém apenas os 100 primeiros

5. Sets: Conjuntos Não Ordenados para Relacionamentos e Unicidade

5.1. Operações básicas

SADD tags:post:1 "redis" "database" "nosql" "redis"
SREM tags:post:1 "nosql"
SMEMBERS tags:post:1           # ["redis", "database"] (ordem não garantida)
SISMEMBER tags:post:1 "redis"  # 1 (verdadeiro)
SCARD tags:post:1              # 2 (quantidade de membros)

5.2. Operações de conjuntos (análogo a joins SQL)

SADD tags:post:1 "redis" "database"
SADD tags:post:2 "redis" "python"
SADD tags:post:3 "python" "web"

# Interseção (posts que têm redis E python)
SINTER tags:post:1 tags:post:2  # ["redis"]

# União (todas as tags únicas)
SUNION tags:post:1 tags:post:2 tags:post:3  # ["redis", "database", "python", "web"]

# Diferença (tags que estão em post:1 mas não em post:2)
SDIFF tags:post:1 tags:post:2  # ["database"]

5.3. Aplicações práticas

# Tags de artigos
SADD artigos:tags:42 "tecnologia" "programação"

# Permissões de usuários
SADD perms:usuario:5 "ler" "escrever" "admin"

# Deduplicação de IPs únicos
SADD visitantes_unicos:2024-01-15 "192.168.1.1"
SADD visitantes_unicos:2024-01-15 "192.168.1.2"
SCARD visitantes_unicos:2024-01-15  # 2

6. Sorted Sets: Ordenação por Score e Ranking em Tempo Real

6.1. Estrutura

Sorted Sets combinam a unicidade dos Sets com um score numérico que define a ordem:

ZADD ranking 100 "jogador1"    # Score 100
ZADD ranking 200 "jogador2"    # Score 200
ZADD ranking 150 "jogador3"    # Score 150

ZRANGE ranking 0 -1            # ["jogador1", "jogador3", "jogador2"] (ordem crescente)
ZREVRANGE ranking 0 -1         # ["jogador2", "jogador3", "jogador1"] (ordem decrescente)
ZREM ranking "jogador1"
ZCARD ranking                   # 2

6.2. Consultas por intervalo de score

ZADD pontuacoes 1000 "ana"
ZADD pontuacoes 2500 "bruno"
ZADD pontuacoes 1800 "carlos"
ZADD pontuacoes 3000 "diana"

# Jogadores com score entre 1500 e 2600
ZRANGEBYSCORE pontuacoes 1500 2600  # ["carlos", "bruno"]

# Quantos jogadores têm score acima de 2000
ZCOUNT pontuacoes 2000 +inf         # 2

# Ranking (posição) de um jogador específico
ZRANK pontuacoes "carlos"           # 1 (baseado em score crescente)
ZREVRANK pontuacoes "carlos"        # 2 (baseado em score decrescente)

6.3. Casos de uso

# Leaderboard de jogo
ZINCRBY leaderboard:jogo1 50 "player:42"

# Fila prioritária (timestamp como score)
ZADD fila_prioritaria 1705315200 "tarefa:1"
ZADD fila_prioritaria 1705315210 "tarefa:2"
ZRANGEBYSCORE fila_prioritaria -inf +inf LIMIT 0 1  # Próxima tarefa mais antiga

# Expiração baseada em timestamp
ZADD sessoes_ativas 1705315200 "sessao:abc123"
ZREMRANGEBYSCORE sessoes_ativas 0 1705315000  # Remove sessões expiradas

7. Estratégias de Modelagem: Quando Usar Cada Tipo de Dado

7.1. Mapeamento de padrões SQL para Redis

Chaves compostas: Use : para simular namespaces e chaves primárias compostas:

# SQL: SELECT * FROM pedidos WHERE usuario_id = 42
# Redis: Chave composta -> "pedidos:42:1001"

# Índices invertidos usando Sets
SADD idx:email:joao@email.com "usuario:5"
SMEMBERS idx:email:joao@email.com  # ["usuario:5"]

7.2. Combinação de tipos

# Hash para dados do usuário
HSET usuario:42 nome "João" email "joao@email.com"

# Set para tags associadas
SADD usuario:42:tags "premium" "vip"

# Sorted Set para histórico de compras (timestamp como score)
ZADD usuario:42:compras 1705315200 "pedido:2001"

7.3. Limitações e boas práticas

Atomicidade: Cada comando Redis é atômico, mas para múltiplos comandos use transações:

MULTI
HSET usuario:42 saldo 1000
SADD usuario:42:permissoes "transferir"
EXEC

Persistência: Redis pode ser configurado com RDB (snapshots) ou AOF (append-only file) para persistência em disco, mas lembre-se: Redis é primariamente um cache em memória.

Boas práticas:
- Use TTL para dados temporários
- Prefira Hashes para objetos complexos em vez de strings JSON
- Use Sets para relacionamentos muitos-para-muitos
- Use Sorted Sets quando precisar de ordenação por peso
- Evite armazenar dados muito grandes (acima de 10MB por chave)


Referências