A tabela de vendas volta de uma cópia, a importação termina sem erro, a contagem bate com a da cópia e o CHECK TABLE responde OK. Ainda assim, alguns itens apontam para vendas que não existem ou para vendas de outros documentos, e o caso mostra por que uma restauração precisa conferir as identidades e as ligações, além da quantidade de linhas.
O relato e as evidências
Depois de uma falha no disco do servidor da loja, a tabela vendas precisa voltar da cópia da noite anterior. Pelo procedimento, a restauração acontece primeiro em um servidor de testes, sem ligação com a matriz nem com as integrações. A importação termina sem erro, a tabela restaurada tem 48.210 vendas, a mesma quantidade medida na própria cópia, e o CHECK TABLE responde OK. O técnico propõe recriar os índices e liberar a tabela, porque os dados voltaram.
No teste da aplicação, porém, alguns itens abrem vendas de outros documentos, e outros não encontram venda nenhuma. Há quatro observações:
- a origem e o destino estão identificados, e a contagem de referência vem do mesmo momento da cópia;
- a tabela vendas restaurada usa o InnoDB;
- a tabela itens_venda guarda o identificador da venda na coluna venda_id, sem chave estrangeira declarada;
- as falhas de correspondência aparecem no teste isolado, sem nenhum uso real do destino.
A importação e a contagem estão conferidas, mas a mesma quantidade de linhas não prova que as identidades e as ligações foram preservadas. Continuam possíveis uma renumeração das vendas, uma mistura de momentos entre as tabelas e uma ligação gravada de forma errada pela aplicação. Recriar os índices não esclarece nenhuma dessas hipóteses, porque o índice só organiza os valores que já estão na tabela. O próximo teste compara os identificadores com os da cópia e examina as ligações dos itens.
A mesma contagem com outras identidades
A cópia de referência fica no banco copia, no mesmo servidor de testes, e a comparação usa dois comandos:
SELECT COUNT(*), MAX(id) FROM vendas;: devolve 48.210 vendas e o maior identificador 52.344 na cópia, e 48.210 vendas e o maior identificador 48.210 na restauração;SHOW CREATE TABLE vendas;: mostra o próximo valor do contador em 52.351 na cópia e em 48.211 na restauração.
Um recorte pelo documento e pelo caixa confirma a troca:
- Documento 4521 do caixa CX01: o identificador 50.877 na cópia e 46.903 na restauração;
- Documento 4522 do caixa CX02: o identificador 30.502 na cópia e 28.127 na restauração;
- Documento 6310 do caixa CX01: o identificador 52.344 na cópia e 48.210 na restauração.
Um item que guardava a venda 52.344 não encontra mais venda nenhuma, porque a restauração não tem identificadores acima de 48.210. Outro item guarda a venda 30.502 e encontra uma linha existente, mas essa linha é outra venda, de outro documento. A definição da tabela restaurada tem a chave primária na coluna id, e nada indica defeito físico: o índice está correto para os valores novos.
A consulta de registros órfãos encontra os itens com identificadores acima de 48.210, mas não encontra o item da venda 30.502, que aponta para uma linha existente e errada. A conferência precisa comparar o significado da ligação, e não só a presença da linha:
SELECT i.id, i.venda_id FROM itens_venda i LEFT JOIN vendas v ON v.id = i.venda_id WHERE v.id IS NULL;: mostra os itens cuja venda não existe;SELECT COUNT(*) FROM itens_venda i JOIN vendas v ON v.id = i.venda_id JOIN copia.vendas c ON c.id = i.venda_id WHERE v.numero_documento <> c.numero_documento OR v.caixa <> c.caixa;: conta os itens que encontram, na restauração, uma venda de outro documento ou de outro caixa.
Se as identidades coincidissem no recorte, a conferência seria ampliada para o momento de cada tabela, para os filtros da aplicação e para a tabela de controle das ordens. Um recorte correto também não validaria, sozinho, a restauração inteira.
O procedimento que gerou o resultado
A sequência usada na restauração mostra a causa. A tabela vendas foi recriada, e as linhas vieram de uma tabela auxiliar com uma lista de colunas sem o id:
INSERT INTO vendas (numero_documento, data_venda, cliente_id, caixa, total, desconto, situacao) SELECT numero_documento, data_venda, cliente_id, caixa, total, desconto, situacao FROM vendas_aux;: copia as vendas sem a coluna id, e o MySQL gera identificadores novos.
O AUTO_INCREMENT numerou as vendas a partir de 1, enquanto a tabela itens_venda continuou com os identificadores antigos. O valor 52.351 do contador estava anotado, mas não foi usado. A importação terminou sem erro porque cada linha nova era válida para a definição da tabela, e nenhuma chave estrangeira conferia a ligação dos itens.
Ajustar o contador para 52.351 não resolve, porque o contador só controla os próximos números e não devolve as identidades das linhas já gravadas. Corrigir só os itens órfãos também não resolve, porque os itens que apontam para uma venda existente e errada continuariam errados. A correção precisa tratar o conjunto, e, como existe uma cópia com as identidades e o destino ainda não teve uso real, uma nova restauração isolada, que preserve o id, é um caminho verificável.
A nova restauração e a validação
Em um segundo banco de testes, a restauração recria a tabela com a definição da cópia e mantém os identificadores:
INSERT INTO vendas (id, numero_documento, data_venda, cliente_id, caixa, total, desconto, situacao) SELECT id, numero_documento, data_venda, cliente_id, caixa, total, desconto, situacao FROM vendas_aux;: copia as vendas com os identificadores originais;ALTER TABLE vendas AUTO_INCREMENT = 52351;: restabelece o próximo valor anotado na cópia.
A conferência devolve 48.210 vendas, o maior identificador 52.344 e o contador em 52.351. O recorte volta a ligar cada documento ao identificador da cópia, a consulta de registros órfãos devolve só os casos que já existiam na cópia, e a comparação dos documentos não encontra nenhum item ligado à venda errada. A tabela de controle das ordens, os índices e as colunas derivadas também são comparados com a cópia, e as telas que antes falhavam abrem as vendas certas no teste controlado.
A liberação ainda depende dos critérios definidos para o retorno, como as buscas principais e o acompanhamento depois da volta. No MySQL 5.1, o InnoDB guarda o contador só na memória e, depois de um reinício, recalcula o próximo número a partir do maior identificador, e por isso o contador também é conferido depois do primeiro reinício.
O registro do atendimento
O registro separa a quantidade de linhas da identidade das linhas:
- Ocorrência: a primeira restauração da tabela vendas manteve as 48.210 linhas, mas trocou os identificadores, e itens passaram a apontar para vendas erradas ou inexistentes;
- Evidências: o maior identificador caiu de 52.344 para 48.210, o contador caiu de 52.351 para 48.211, e o recorte mostrou os mesmos documentos com outros identificadores;
- Causa: a cópia das linhas usou uma lista de colunas sem o id, e o AUTO_INCREMENT gerou números novos;
- Correção: uma segunda restauração isolada preservou os identificadores e o contador anotado;
- Validação: as ligações dos itens, a tabela de controle e as telas afetadas foram conferidas com a cópia;
- Pendências: os critérios de liberação, o acompanhamento depois do retorno e a conferência do contador depois do primeiro reinício.
No suporte
Antes de liberar uma restauração, convém comparar com a própria cópia o maior identificador, o contador e um recorte de documentos, além da contagem. Uma importação sem erro mostra que o banco aceitou os comandos, e não que a lógica da aplicação foi preservada.
Para guardar
- A mesma quantidade de linhas pode esconder outras identidades.
- Uma ligação que encontra uma linha pode encontrar a linha errada.
- O ajuste do contador controla os próximos números e não corrige as identidades já gravadas.
- A reconstrução dos índices não refaz as ligações mantidas pela aplicação.
- A restauração passa por um teste isolado e por critérios de liberação antes do retorno.
A consulta de registros órfãos voltou vazia em uma restauração. Isso prova que as ligações estão certas?
Não. A consulta encontra os itens que apontam para uma venda inexistente, mas não os que apontam para uma venda existente e errada. A comparação com a cópia, pelo documento e pelo caixa da venda que cada item encontra, mostra essas ligações trocadas.
Se as estações já tivessem gravado vendas novas na tabela restaurada errada, bastaria restaurar de novo com o id?
Não como uma troca simples. As vendas novas também receberam identificadores, e uma nova restauração as perderia ou poderia repetir os números delas. Essas vendas precisam ser preservadas e reconciliadas no plano de retorno antes da substituição dos dados.