terça-feira, 28 de dezembro de 2010

PostgreSQL migrando uma database de tablespace


    No PostgreSQL diferente do Oracle uma tablespace é um local de armazenamento de dados do banco, deste modo imagine o seguinte cenário: 

Dois HDs, um onde está a pg_default(tablespace padrão do PostgreSQL) com 99% de uso e o outro HD com uma boa capacidade e performance com 1% de uso. Então chegou a hora de migrar uma de suas databases para outra tablespace.

Primeiro criamos uma nova tablespace apontando para o path do novo HD: 

CREATE TABLESPACE "external_data" OWNER postgres
LOCATION '/data/Archives1/pg_external_data';

Onde '/data/Archives1/pg_external_data' é o caminho absoluto da nova tablespace. 

Verificação das tablespaces existentes:

SELECT spcname AS Tablespace, pg_size_pretty(pg_tablespace_size (spcname)) AS Tamanho, spclocation AS Caminho
FROM pg_tableSpace;

tablespace | tamanho | caminho
---------------+---------+----------------------------------
pg_default | 53 GB |
pg_global | 609 kB |
external_data | 4 bytes | /data/Archives1/pg_external_data
(3 rows)

A saída acima é um exemplo.


Agora o índio veio tem dois caminhos, um migra-se objeto por objeto(tabela, índice e la la la), ou faz um dump da database e se importa depois, vamos pelo caminho mais fácil, que segue:

Criação do dump:


$ nohup /opt/pgsql/bin/pg_dump -h 127.0.0.1 -p 5432 -U postgres -f /data/Archives1/mydump-12-08-2010.dmp my_db &


Criação da database auxiliar:


CREATE DATABASE test
WITH ENCODING='UTF8'
OWNER=postgres
CONNECTION LIMIT=-1
TABLESPACE=external_data;

Agora vamos importar as crianças:

$ nohup /opt/pgsql/bin/psql -U postgres -h 127.0.0.1 test < /data/Archives1/mydump-12-08-2010.dmp &

Virando a chave:

Ativando database auxiliar para produção:


ALTER DATABASE my_db RENAME TO my_db-old;
ALTER DATABASE test RENAME TO my_db;

Liberação de espaço ao dropar database em desuso:


DROP DATABASE my_db-old;

sexta-feira, 3 de dezembro de 2010

MySQL - Salvando o Innodb corrompido no MySQL

O que fazer quando seu MySQL 5.x retorna a seguinte mensagem no log:


101203 14:32:07  InnoDB: Page checksum 3473125734, prior-to-4.0.14-form checksum 1097980787
InnoDB: stored checksum 3473125734, prior-to-4.0.14-form stored checksum 143311008
InnoDB: Page lsn 0 3817445983, low 4 bytes of lsn at page end 3816433326
InnoDB: Page number (if stored to page already) 1115,
InnoDB: space id (if created with >= MySQL-4.1.1 and stored already) 138
InnoDB: Page may be an index page where index id is 0 373
InnoDB: (index PRIMARY of table prod/item)
InnoDB: Database page corruption on disk or a failed
InnoDB: file read of page 1115.
InnoDB: You may have to recover from a backup.
InnoDB: It is also possible that your operating
InnoDB: system has corrupted its own file cache
InnoDB: and rebooting your computer removes the
InnoDB: error.
InnoDB: If the corrupt page is an index page
InnoDB: you can also try to fix the corruption
InnoDB: by dumping, dropping, and reimporting
InnoDB: the corrupt table. You can use CHECK
InnoDB: TABLE to scan your table for corruption.
InnoDB: See also InnoDB: http://dev.mysql.com/doc/refman/5.0/en/forcing-recovery.html
InnoDB: about forcing recovery.
InnoDB: Ending processing because of a corrupt database page.


Primeiro para subir o banco, altere o argumento dentro do arquivo my.cnf:
innodb_force_recovery = 4
Salve o arquivo e inicie o MySQL.
Após faça um dump completo de todas as databases:
# mysqldump -A -u root -v > /tmp/all.dmp
Com um dump em mãos podes DROPAR todas as databases. Mas antes faça uma lista delas:
# mysql --batch --skip-column-names -u root -e "SHOW DATABASES" > /tmp/mysql.db.list
# for db in `cat /tmp/mysql.db.list`; do mysql -u root -e "DROP DATABASE $db";   echo -e "Dropped $db"; done
Mova o diretório base do MySQL para exemplo 'data-old'. 
Recrie a pasta 'data' do MySQL e coloque como owner desta pasta o usuário de execução do 'mysqld'. 
Inicialize uma nova database MySQL e importe o dump criado anteriormente:
# mysql -u root < /tmp/all.dmp

Banco recriado e informações persistidas sem mais erros de 'Innodb'.