Você está na página 1de 4

Firebird Expert - Índices

Por Ann Harrison

Resumo

O Firebird difere de várias formas significativamente de outros sistemas gerenciadores


de bancos de dados relacionais. Entender as diferenças permitirá a você criar aplicações
Firebird com melhor desempenho.

Público alvo: desenvolvedores experientes de aplicações de banco de dados.

A mudança para o Firebird pode ser desconcertante para desenvolvedores que já tenham
trabalhado com outros sistemas gerenciadores de bancos de dados. Na teoria, o banco de
dados relacional separa o projeto lógico de uma aplicação do armazenamento físico dos
dados, permitindo aos desenvolvedores concentrarem-se em quais dados eles querem
que suas aplicações acessem, ao invés de se preocupar em como os dados devem ser
recuperados. Na prática, o mecanismode cada sistema gerenciador de bancos de dados
realiza alguns tipos de acesso mais rapidamente do que os outros. Os desenvolvedores
geralmente aprendem os métodos de otimização que funcionam com o SGBD utilizado
por eles.

Desenvolvedores familiarizados com Oracle ou MSSQL percebem que os índices do


Firebird, o modelo de concorrência, e a recuperação de falhas, comportam-se de
maneira diferente desses SGBDs. Entender e trabalhar com estas diferenças fará a
mudança para o Firebird menos tensa e mais bem sucedida. Este documento foca as
características incomuns dos índices do Firebird.

1.1.3 Tipo de índices

O Firebird suporta somente um tipo de índice: uma variação do b-tree. Índices podem
ser únicos ou permitir duplicidades; Eles podem ter uma chave simples ou composta,
ascendente ou descendente.

1.1.4. Localização do registro

Muitos bancos de dados agrupam registros no índice da chave primária, seja


armazenando os dados diretamente no índice ou usando a chave para agrupar os
registros. Em um sistema balanceado, agrupar na chave primária torna as buscas pela
chave primária muito eficientes. Se o registro inteiro for armazenado no índice, o nível
de dados torna-se muito extenso, fazendo todo o índice mais profundo e dispendioso
para ser percorrido do que somente uma consulta superficial, num índice mais denso. O
agrupamento de registros (clustering) pode resultar em desperdício de armazenamento
ou sobrecarga dependendo da especificação de projeto e da distribuição de dados.

O Firebird armazena os registros em páginas de dados, usando a página mais acessível


com espáco suficiente disponível . Índices são armazenados em páginas de índices e
contém um registro localizador na folha nó.
Custo de acesso do índice primário e secundário: quando o dado está agrupado na chave
primária, o acesso por ela é muito rápido. O acesso através de índices secundários é
mais lento, especialmente quando a chave secundária do índice usa a chave primária
como um registro localizador. Nesses casos, a localização pelo índice secundário
transforma-se em duas procuras em índice.

No Firebird, o custo de acesso das procuras pelos índices primário e secundário é


idêntico.

1.1.5 Estratégia de acesso

A maioria dos sistemas de banco de dados lê um nó no índice e então recupera os dados


– Esta técnica também faz com que seja necessário ficar indo pra lá e pra cá entre as
páginas de índices e os dados, o que pode ser resolvido pelo correto controle de
alocação, assumindo que o DBA tem tempo e habilidade para isto. Para índices não
agrupados, esta técnica também resulta em re-ler as páginas de dados.

O Firebird penera os localizadores para os registros qualidifcados pelo índice,


construindo um bitmap de registros localizadores, e então lendo os registros na ordem
física de armazenamento.

1.1.6 Otimização de índice

Como a estratégia de acesso amarra o acesso ao índice e aos registros, a maioria dos
otimizadores de banco de dados devem escolher um índice por tabela como caminho de
acesso ao dado. O Firebird pode usar diversos índices de uma tabela através de
operações de AND e OR nos bitmaps criados através dos índices, antes de acessar
qualquer dado.

Se você tem uma tabela onde vários campos diferentes são usados para restringir a
recuperação de dados de uma consulta, a maioria dos bancos de dados requer que você
defina um único índice que inclua todos os campos. Por exemplo, se você esta
procurando por um filme que foi feito em 1964, dirigido por Stanley Kubrick, e
distribuído pela Columbia, você precisará de um índice por Ano, Diretor e
Distribuidora. Se você sempre procura todos os filmes dirigidos por Stanley Kubrick,
você também precisará de um índice definido apenas pelo diretor, etc. Com o Firebird,
você poderia definir um índice por Diretor, um por Distribuidora e um por Ano, e eles
poderiam ser utilizados em várias combinações.

1.1.7 Cadeia longa de duplicados

Alguns bancos de dados (Firebird 2 por exemplo) são melhores que outros (Firebird 1.x,
por exemplo) removendo dados de cadeias longas de duplicados (>10000) em índices.
Se você precisa de um índice de um campo com baixa seletividade para o banco de
dados Firebird 1.x, deveria criar uma chave composta pelo campo que você deseja
seguido de um campo mais seletivo. Por exemplo, se você tem um índice por
DataPagamento na tabela Contas, e todos os registros são armazenados com o valor null
quando a conta está em aberto, e então modificado quando a conta é paga, você deveria
criar um índice composto por DataPagamento e NumeroConta, ao invés de um índice
com um único campo DataPagamento.
1.1.8 Índices de custo de dados

SGBDs que não são baseados no versioning resolvem algumas consultas (counts por
exemplo) lendo o índice sem realmente ler os registros de dados. Índices no Firebird
(como no PostgreSQL e outros banco de dados nativamente versioning) contêm
entradas que não são ainda visíveis para outras transações e entradas que não são mais
relevantes para transações ativas. A única forma de saber se uma entrada no índice
representa o dado visível para uma transação em particular é lendo o registro.

O tópico versão do registro merece uma longa discussão. Resumidamente, quando o


Firebird armazena um novo registro, ele marca o registro com um identificador de qual
transação o criou. Quando o registro é modificado, ele cria uma nova versão do registro
marcada com o identificador de qual transação fez a modificação. Esse registro aponta
para a versão anterior do mesmo registro. Até que a transação que criou a nova versão
seja terminada com um commit, todas as outras transações continuarão a ler a versão
antiga do registro.

Neste exemplo acima, quando uma transação modifica o campo de índice


DataPagamento, o Firebird cria uma nova versão do registro contendo a nova data e o
identificador da transação que fez a alteração. O índice daquele campo neste momento
tem duas entradas para este registro, uma para o original (null) e outra para o novo valor
de DataPagamento.

O índice não tem informação suficiente para determinar quais entradas deveriam ser
contadas para responder uma consulta como: select count(*) from contas where
DataPagamento is not null.

1.1.9 Tamanho da chave do índice

Na versão Firebird 1.x, o tamanho total de uma chave de índice tem que ser menor que
252 bytes. Índices de chaves compostas e índices com uso de collation não binárias são
mais restritivos por razões descritas na seção Compactação da chave de índice. O
Firebird 2 permite chaves com até 1/4 do tamanho da página, ou um máximo de 4 Kb.

1.1.10 Representação da chave de índice

O Firebird converte todas as chaves de índice em um formato que pode ser comparado
por byte-wise. Com exceção dos campos inteiros de 64bit, todos os campos chave
numéricos e datas são armazenados como inteiros de precisão dupla, e os números de
precisão dupla são manipulados para serem comparados byte a byte. Quando
executando uma procura por índice, o Firebird converte o valor procurado para o
mesmo formato da chave armazenada. Para o desenvolvedor, isto significa que não
existe diferença básica de velocidade entre índices de strings, números e datas. Todos os
índices são comparados por byte-wise, sem levar em consideração seus tipos de dados
originais.

1.1.11 Compactação da chave de índice.

Chaves de índice do Firebird são sempre gravadas com compactação de prefixo e


sufixo. A compactação de sufixo remove os espaços em branco posteriores dos campos
string e os zeros a esquerda dos campos numéricos. Lembre-se que a maioria dos
valores são armazenados com precisão dupla e os zeros à esquerda não são
significativos. A compactação de sufixo é feita para cada campo da chave em uma
chave composta sem perda dos limites dos campos da chave. Após remover os espaços
em branco e os zeros posteriores, o código de compactação do índice faz com que o
tamanho seja múltiplo de 4 bytes, e insere bytes de marca a cada 4 bytes para indicar a
posição do campo na chave.

Considere o caso da chave com três campos com este conjunto de valores:

“abc “, “def “, “ghi “


“abcdefghi “, “ “, “ “

Simplesmente eliminando os espaços em branco posteriores fariam 2 conjuntos de


valores iguais. Ao invés disto o Firebird converte o primeiro conjunto de valores da
chave para :

“abc 1def 2ghi 3”


e o segundo em
“abcd1efgh1i 1 2 3”.

O Firebird versão 1.x faz a compactação de prefixo das chaves de índice enquanto elas
são armazenadas nas páginas de índices. Ele armazena a primeira chave em uma página
sem compactação de prefixo. As chaves subseqüentes são armazenadas depois de
substituídos os bytes principais que combinam com a mesma seqüência na chave prévia
por um simples byte contendo o número de bytes que foram saltados. As duas chaves
acima deveriam ser armazenadas desta forma:

“0abc 1def 2ghi 3” “3d1efgh1i 1 2 3”

Uma entrada de índice que combina perfeitamente com a entrada previa é armazenada
como um byte simples que contém seu tamanho. O Firebird 2 também realiza a
compactação de prefixo, mas usa uma representação mais densa.

A combinação das técnicas de compactação elimina algumas das regras sobre a


construção das chaves. A compactação de sufixo ocorre em todos os segmentos da
chave, assim campos varchar deveriam ser colocados em seu local lógico em uma chave
composta, não forçando-os para o fim. Por outro lado se parte da chave composta tem
um número grande de valores duplicados, isto deveria estar no início da chave
composta, para levar vantagem da compactação de prefixo.

Este documento foi escrito por Ann Harrison em Junho de 2005, e está sobre copyright
Srta. Harrison e IBPhonix. Você deve reproduzi-lo literalmente, incluindo esta
anotação. Você talvez atualize, corrija ou expanda o material, desde que você inclua a
notação do trabalho original foi produzido por Ms. Harrison e IBPhoenix, e a tradução
para o português foi feita por Gleison Gibellato da Silva e Moacir Flávio Gonçalves.

Essa versão do artigo teve a tradução ligeiramente modificada por Carlos H. Cantu.

Você também pode gostar