Translate

Pesquisar este blog

segunda-feira, 30 de março de 2015

Escrevendo os dados no Firebird rapidamente sem Forced Writes.

O Forced Writes é um parâmetro da database que pode ser mudado em tempo de execução.

Não é recomendado, porque pode levar a database à corrupção de dados em caso de falha do sistema, se o seu hardware não garantir.

Mesmo assim você pode precisar carregar os dados, como de uma importação esporádica, então pode ser útil.

Fazendo backup full e incremental com o Firebird

Firebird é um banco de dados muito robusto, mas também simples e fácil de utilizar.

Ele suporta o "basico" do padrão ANSI, sem muito mais que isso, ao contrário do PostgreSQL.

Também o sistema de backup incremental do Firebird, é mais simples que o do PostgreSQL. No Firebird você só precisa chamar o comando nbackup que vem com o banco.

A parte importante deste comando é a opção  -B. Ela indica o nível de backup utilizado.

Mas o que são níveis de backup?

Um backup nível 0 significa um backup full. Todos os dados irão para o backup.
Um backup nível 1 significa que serão salvos os dados desde o último backup nível 0.
Um backup nível 2 significa que serão os dados desde o último backup nível 1.
...

E assim por diante.

O backup full (de toda a database).
$ nbackup -B 0 -U sysdba -P senha teste.fdb teste.fbk
 
Fazendo um backup nível 1 ("diário") 
$ nbackup -B 1 -U sysdba -P senha teste.fdb teste_30032015.fbk

Fazendo um backup nível 2 ("horário")
$ nbackup -B 2 -U sysdba -P senha teste.fdb teste_30032015_1300.fbk


domingo, 29 de março de 2015

Pegando a lista de tabelas em SQL com Firebird

 Para ver as tabelas no Firebird, use o seguinte SQL:

select rdb$relation_name
from rdb$relations
where rdb$view_blr is null
and (rdb$system_flag is null or rdb$system_flag = 0)
order by 1


Para ver a lista de campos de uma tabela, use o SQL:

select c.rdb$type_name, a.rdb$field_name, b.RDB$FIELD_SCALE
from rdb$relation_fields a, rdb$fields b, rdb$types c
where a.rdb$relation_name = 'MINHA_TABELA'
and a.RDB$FIELD_SOURCE = b.rdb$field_name
and b.rdb$field_type = c.rdb$type
and c.rdb$field_name = 'RDB$FIELD_TYPE'


Para ver os campos com chave primária:

select b.rdb$field_name
from RDB$relation_constraints a, RDB$INDEX_SEGMENTS b
where a.rdb$constraint_type = 'PRIMARY KEY'
and a.rdb$index_name = b.rdb$index_name
and a.rdb$relation_name = 'MINHA_TABELA'


sábado, 28 de março de 2015

Particionando tabelas no PostgreSQL usando herança

No PostgreSQL existe como particionar tabelas usando herança de classe.

Esse sistema funciona um pouco como o MySQL, que usa particionamento padrão. Mas também é mais complexo.

Primeiro criamos uma tabela-base contendo os campos. Ela é abstrata, ou seja: ela não terá registros, apenas suas descendentes:

create table all_logs (
id bigserial,
date timestamp default now(),
id_user int,
action varchar(20),

check(false) no inherit
);

A constraint check(false) no inherit só funcionará se o banco for versão 9.2 ou superior. Se ainda não suporta, omita.

Observe que esta tabela não possui chave primária nem chaves estrangeiras. Eles devem existir apenas nas tabelas-filhas desta.

Estas são as tabelas filhas, que armazenam os registros. Veja que elas "herdam"os campos da tabela all_logs como em orientação a objetos:

create table logs_2015_01 (

primary key(id),
check(date between '2015-01-01' and '2015-02-01')
) inherits (all_logs);


create index on logs_2015_01(date);

create table logs_2015_02 (

primary key(id),
check(date between '2015-02-01' and '2015-03-01')
) inherits (all_logs);


create index on logs_2015_02(date);


  1. A cláusula inherits faz ela herdar da tabela all_logs. Mas é preciso definir os campos chaves primária e estrangeiras, bem como os índices em cada tabela filha. Definir na tabela-base, as filhas não vão herdar essas constraints.
  2. A cláusula check é importante para performance: uma pesquisa pela tabela all_logs usando o campo date fará excluir, das tabelas-filhas, todos os meses que não correspondem às datas no check, sem ler seus dados.

Inserindo registros.
Para inserir na tabela all_logs, é necessário criar uma trigger que indique para qual tabela-filha redirecionar o registro.

CREATE OR REPLACE FUNCTION insert_logs()
RETURNS TRIGGER AS $$
BEGIN
    IF ( NEW.date between '2015-01-01' AND '2015-02-01' ) THEN
        INSERT INTO logs_2015_01 VALUES (NEW.*);
    ELSIF ( NEW.date between '2015-02-01' AND '2015-03-01' ) THEN
        INSERT INTO logs_2015_02 VALUES (NEW.*);
    ELSE
        RAISE EXCEPTION 'Date fora de alcance. Corrija a função insert_logs()';
    END IF;
    RETURN NULL;
END;
$$
LANGUAGE plpgsql;


CREATE TRIGGER insert_logs
    BEFORE INSERT ON all_logs
    FOR EACH ROW EXECUTE PROCEDURE insert_logs();


Então você pode inserir registros usando INSERT na tabela all_logs. A trigger redirecionará para a tabela filha adequada.

Fazendo pesquisas:
No exemplo nós definimos a  partição pelo campo date. uma instrução de SELECT por este campo fará o banco escolher as partições corretas por causa da cláusula check.

SELECT * from all_logs where date between '2015-01-05' and '2015-01-10'
Isto, por exemplo, fará com que o banco utilize apenas a tabela logs_2015_01, porque a 2015_02 usa um check(date between '2015-02-01' and '2015-03-01').

Excluindo partições:






Basta dropar a tabela que você deseja excluir.
drop table 2015_01


terça-feira, 24 de março de 2015

Criando uma tabela externa no Firebird, em arquivo texto fixo

Criar uma tabela externa no firebird requer que o parâmetro ExternalFileAccess esteja devidamente setado no arquivo firebird.conf,por exemplo:

ExternalFileAccess = Restrict E:\FB;E:\FB2

Para criar a tabela usa-se um comando como:

CREATE TABLE EXT4 EXTERNAL 'E:\FB\MYFILE3.TXT'
(
  ID char(13) character set none,
  NOME char(20)
character set none,
  break char(1) character set none 
);

Observe que para criar um arquivo texto o tipo de dados mais adequado é char para todos os campos, caso contrário, o banco usará definições binárias pouco fáceis de utilizar.

Observe também que se utilizar character set utf8 o Firebird vai usar campos 4 vezes maiores do que definido nas tabelas. Assim um char(20) ocupará 80 bytes!!

Fazendo operações de DDL mais rápidas no PostgreSQL

Operações como CREATE INDEX, ALTER TABLE, etc são conhecidas como operações de DDL.

Elas podem ser mais rápidas se combinados alguns fatores como:
-Setar o asynchronous_commit.
-Setar o maintenance_work_mem para um valor alto o suficiente.
-O valor de checkpoint_segments no arquivo postgresql.conf for alto o suficiente (é necessário reinciar o servidor).

O valor de checkpoint_segments por default é 3, muito baixo, se há escrita intensa no servidor é possível colocar em shared_buffers/16 Megabytes.


$ show maintenance_work_mem;

$ set local maintenance_work_mem to '1024MB';
$ set synchronous_commit to off;
$ create index concurrently on minhatabela using gin(campo_tsvector_que_demora_muito_por_exemplo);

Criando índices sem bloquear a tabela no PostgreSQL

Índices criados com a cláusula CONCURRENTLY não travam a tabela enquanto ele é criado. Isto é uma vantagem interessante do elefante.

psql -U usuario bancodedados
$ create index concurrently on minhatabela(meucampo);
$ \q


Usando asynchronous commit com PostgreSQL.

Asynchronous commit é uma opção para as transações rodarem mais rápido no PostgreSQL, a um custo de elas serem perdidas em caso de um crash repentino no banco.

Para ativar o  asynchronous commit apenas ponha o parâmetro syncrhonous_commit para off. Não é necessário parar o banco para isso.


psql -U usuario bancodedados
$ SET LOCAL synchronous_commit TO OFF;
$ create index concurrently on minhatabela(meucampo);
$ \q