Buscar

Prévia do material em texto

FATEC/SO - Faculdade de Tecnologia de Sorocaba 
Departamento de Processamento de Dados 
Curso de Tecnologia em Processamento de Dados 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Processamento e otimização de consultas 
em bancos de dados relacionais 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Apostila elaborada pelo Professor Antonio Cesar de Barros Munari 
 
 
Aspectos físicos do armazenamento de dados 
Aspectos físicos do armazenamento de dados 
A discussão sobre os aspectos físicos do armazenamento de dados encontrada neste 
material utilizará como exemplo em diversas situações o modelo de dados referente a um 
controle bancário simplificado, cuja descrição geral é fornecida a seguir, juntamente com 
o modelo conceitual correspondente e o esquema lógico da base de dados. 
O caso do controle bancário simplificado 
O Banco Popular S/A possui inúmeras agências no interior do estado de São Paulo, 
contando atualmente com um número significativo de clientes. O procedimento para 
abertura de uma conta corrente é bastante rápido e simples, não havendo necessidade de 
se fazer um depósito inicial, já que alguns clientes utilizam a conta apenas para receber os 
seus salários. Como todo banco, existe a possibilidade da abertura de uma conta corrente 
conjunta (no caso de casais, por exemplo). Toda conta corrente está associada a uma 
agência bancária, mas nada impede que um cliente possua contas em agências diferentes, 
se isso for de seu interesse. Os movimentos de cada conta corrente (créditos e débitos) 
são armazenados pelos sistemas informatizados do banco, de maneira a tornar possível a 
emissão dos extratos bancários a que cada cliente tem direito. Além disso devem ser 
consideradas também as seguintes regras de negócio: 
a) Não existem duas contas corrente com o mesmo número, mesmo que em 
agências diferentes; 
b) Todo cliente possui uma senha específica para cada uma de suas contas 
corrente e se a conta for conjunta cada titular possui sua própria senha. 
c) Toda movimentação em conta corrente recebe um número seqüencial; 
d) O sistema deve permitir saber a data em que uma conta corrente foi aberta; 
e) Toda agência possui, além de um código, também um nome; que é utilizado 
em alguns documentos internos do banco. 
Modelos e níveis de abstração em um banco de dados 
Uma descrição como a apresentada para o funcionamento do controle das contas corrente 
pode ser expressa graficamente através de um diagrama de alto nível que procura 
representar com precisão os diversos elementos envolvidos, seus dados descritivos e 
relacionamentos relevantes. Esse tipo de diagrama representa aquilo que chamamos de 
modelo conceitual, onde o nível de abstração utilizado é muito alto e que tem por 
finalidade capturar os principais aspectos da realidade que sejam de interesse dentro do 
escopo do problema. Um instrumento típico para representar um modelo conceitual é o 
diagrama Entidade / Relacionamento, como o utilizado na figura 1 para modelar as 
especificações gerais do caso do controle bancário. 
 
Aspectos físicos do armazenamento de dados 
Figura 1: Modelo conceitual para o controle bancário simplificado. 
O modelo conceitual é, entretanto, muito abstrato para receber uma implementação direta 
sob um SGBD, pois deve ser independente da tecnologia computacional, já que procura 
retratar as coisas tais como ocorrem no mundo real. Assim, esse modelo de mais alto 
nível precisa ser detalhado de maneira a permitir sua materialização dentro de um 
produto de banco de dados. O modelo (ou esquema) lógico procura detalhar as 
especificações do nível conceitual para uma tecnologia computacional específica (como 
por exemplo a relacional ou a orientada a objetos) considerando ainda as características e 
limitações de um determinado produto de banco de dados. A figura 2 apresenta um 
diagrama lógico para uma implementação relacional do caso do controle bancário, e foi 
obtida a partir das especificações constantes no modelo conceitual mostrado 
anteriormente na figura 1. 
O esquema lógico é muito mais específico que o conceitual, mas ainda é genérico o 
suficiente para comportar mais de uma implementação física. Diversos aspectos de mais 
baixo nível podem ainda ser considerados para que as estruturas de dados 
correspondentes venham a ser construídas no banco de dados. A figura 3 procura mostrar 
a relação entre esses três níveis de abstração, dos quais o nível físico é aquele que merece 
maior atenção neste material. 
 
Cliente
Conta
Corrente
Agência
MovimentoMantém
Pertence
Possui
@Cód. Cliente
Nome
Endereço
Telefone
Dados Pessoais
Senha
@ Núm. Conta
Data Abertura
Saldo Atual
@ Núm. Mov.
Data Movim.
Tipo Mov.
Valor Movim.
Descr. Movim.
@ Núm. Agênc.
Nome Agência
Endereço
Telefone
Aspectos físicos do armazenamento de dados 
Clientes Contas
Agencias
Movimentos
Senha
CliContas
CdCliente
NmCliente
EndCliente
TelCliente
RGCliente
CPFCliente
CdCliente
NrConta
NrConta
DtAbertura
CdAgencia
VrSaldo
CdAgencia
NmAgencia
EndAgencia
TelAgencia
NrMov
NrConta
DtMov
TpMov
VrMov
DsMov
VrSaldoSexo
 
Figura 2: Esquema lógico (relacional) para o controle bancário simplificado. 
 
 
 
 
 
 
 
 
 
 
 
Figura 3: Relação entre os 3 níveis de abstração em um projeto de banco de dados. 
Modelo conceitual 
(coisas, objetos, entidades, 
relacionamentos, etc) 
Modelo lógico 
(tabelas, tipos de dados, regras 
de nomes, etc) 
Modelo físico 
(arquivos, páginas em disco, 
índices, etc) 
 
Realidade 
Hardware / Software 
Alto nível 
Baixo nível 
Aspectos físicos do armazenamento de dados 
Estruturas de armazenamento físico 
Armazenamento de dados 
O conteúdo de um banco de dados é fisicamente armazenado na forma de arquivos em 
disco e por isso está sujeito às características e limitações desse tipo de dispositivo, 
valendo aqui todos aqueles elementos básicos de gerenciamento em disco que geralmente 
são abordados em uma disciplina introdutória sobre sistemas operacionais e em obras 
como [TANEMBAUM, 1995]. A quantidade e variedade de tipos de arquivos utilizados 
pelos diversos SGBDs varia bastante, mas os princípios básicos de armazenamento dos 
dados são geralmente comuns. É importante lembrar que qualquer processamento sobre 
os dados ocorre na memória principal, o que implica na constante movimentação (leituras 
e gravações físicas) de informação entre o disco e a memória durante a operação do 
SGBD. 
Figura 4: Movimentação de dados entre a memória e o disco pelo SGBD. 
Os arquivos em disco de um banco de dados são organizados na forma de blocos ou 
páginas, que podem conter dados ou metadados. Uma operação de leitura física traz do 
disco o conteúdo de toda uma página, o que pode significar que mais de uma linha está 
sendo lida naquela operação, uma vez que tipicamente uma página possui um valor na 
faixa entre 2Kb e 32Kb e por isso geralmente contém dados de mais de uma linha de 
tabela, como pode ser visualizado na figura 5. 
Aspectos físicos do armazenamento de dados 
Movimentos 
 NrMov NrConta DtMov TpMov VrMov DsMov VrSaldo 
 <header da página> 
Página 1 1 1021 10/08/95 C R$ 500,00 Deposito R$ 500,00 
 2 1022 20/09/95 C R$ 750,00 Deposito R$ 750,00 
 3 1021 20/09/95 D R$ 120,00 Cheque R$ 380,00 
 
 <header da página> 
Página 2 4 1023 22/09/95 C R$ 400,00 Deposito R$ 400,00 
 5 1024 10/10/95 C R$ 920,00 Deposito R$ 920,00 
 
 
Figura 5: Distribuição dos dados da tabela Movimentos pelas páginas no disco. 
O exemplo da figura mostra que as 3 primeiras linhas da tabela Movimentos são 
armazenadas na mesma página física em disco, o que significa que quando uma delas 
deve ser lida, todas as outras são lidas também, já que aquela página inteira vai para a 
memória principal. Observe também que há um espaço livre em cada página, que é útil 
para acomodar algumas modificações e inclusões de dados na tabela. A figura também 
mostra queuma página possui, além de dados, algumas informações de controle sobre o 
seu conteúdo, chamadas metadados, como por exemplo a identificação da página, o seu 
tipo (se é uma página de dados ou de índice), quantas linhas ela contém, total de espaço 
livre, a data e hora da última atualização, etc. Os metadados costumam ficar armazenados 
em áreas reservadas no ínicio de cada página, chamadas de cabeçalhos ou headers. 
Também uma linha possui metadados, que indicam por exemplo o seu número de 
colunas, o tamanho útil de cada uma, identificadores de linha, etc. 
Uma linha de tabela é identificada por meio de um número interno que muitas vezes 
recebe o nome de RID (Row ID) ou TID (Tuple ID). A composição desse número varia 
conforme o SGBD utilizado, mas tipicamente envolve pelo menos o número do arquivo, 
do bloco e da linha, o que faz com que um RID possa ser considerado como uma espécie 
de ponteiro para a linha. No caso do Oracle 8, por exemplo, um RID possui 10 bytes de 
tamanho, e é composto por 4 informações, conforme mostra a figura 6. 
 
 
 
 
Figura 6: Organização interna de um RowId no Oracle 8. 
Os tipos de dados suportados pela linguagem de manipulação de dados (DML) do SGBD 
são implementados no nível físico através de estruturas de dados próprias, com uma 
significativa variação entre um produto e outro. O quadro a seguir procura mostrar como 
os tipos de dados mais comuns são implementados no SGBD Oracle 8. 
RowId: 00003894024033750001 
 
Número do objeto Número do arquivo Número da página Número da linha 
00003894 024 03375 0001 
 
Aspectos físicos do armazenamento de dados 
Tipo Descrição 
Char Possui um indicador de tamanho de 1 byte (para colunas com até 250 bytes) 
ou 3 bytes (para colunas com mais de 250 bytes). O conteúdo da coluna é 
preenchido com espaços em branco à direita, até o tamanho da coluna. São 
armazenados na linha na mesma ordem do create table. 
Varchar2 Possui um indicador de tamanho de 1 ou 3 bytes. São armazenadas na linha 
na mesma ordem do create table. Se a coluna contiver um nulo, isso é 
sinalizado como tamanho = 0. 
Number Não implementa diretamente os tipos numéricos convencionais, como 
Integer, Float, etc. Em vez disso, utiliza uma estrutura de tamanho variável, 
cujo tamanho depende dos valores a serem armazenados. 
Date Ocupa 7 bytes e inclui século, ano, mês, dia, hora, minuto e segundo. 
Com base nas informações que temos, podemos estimar com alguma precisão o tamanho 
real de uma linha de tabela. Vamos imaginar a tabela Movimentos, cuja estrutura é 
apresentada na figura 7. 
Coluna Tipo / Tamanho Observações 
NrMov NUMBER( 12 ) Número do movimento 
NrConta CHAR( 4 ) Número da conta 
DtMov DATE Data do movimento 
TpMov CHAR( 1 ) Tipo de movimento 
VrMov NUMBER( 12, 2 ) Valor do movimento 
DsMov VARCHAR2( 20 ) Descrição do movimento 
VrSaldo NUMBER( 12, 2 ) Saldo da conta após o movimento 
Figura 7: Descrição da estrutura da tabela Movimentos. 
O cálculo é o seguinte: 
Núm.bytes Descrição 
3 Cabeçalho de linha 
7 Indicadores de tamanho das colunas (7 colunas com tamanho < 250 bytes) 
4 Tamanho fixo da coluna NrConta 
7 Tamanho fixo da coluna DtMov 
1 Tamanho fixo da coluna TpMov 
9 Tamanho das colunas NrMov, VrMov, VrSaldo (aproximadamente)* 
20 Tamanho máximo da coluna DsMov 
51 Tamanho total aproximado por linha 
Aspectos físicos do armazenamento de dados 
*A quantidade de bytes para colunas numéricas é estimada com base em [LONEY & THERIAULT, 2000]. 
Tabelas com colunas de tamanho variável podem ser problemáticas do ponto de vista da 
alocação de espaço em disco, na medida em que mudanças no conteúdo de uma coluna 
podem levar ao aumento do tamanho físico da linha no disco. Em um caso extremo, uma 
linha armazenada em uma página pode receber uma atualização que modifique seu 
tamanho físico e force o SGBD a armazenar uma parte dessa linha em uma página e outra 
parte em outra página. Dizemos então que essa linha sofreu um encadeamento entre dois 
blocos e sempre que for necessário recuperar essa linha, o gerenciador deverá ler as duas 
páginas a partir do disco, degradando o desempenho geral da consulta. Para minimizar a 
ocorrência desse tipo de problema, um espaço físico geralmente é reservado em cada 
página para acomodar futuras extensões no tamanho das linhas já armazenadas na página. 
Essa margem de segurança, expressa em percentuais, é chamada de PCTFREE em alguns 
dialetos SQL (como do Oracle e SQL Base, por exemplo) e informada no momento da 
criação da tabela. Um valor típico para esse parâmetro é 10%, o que significa que novas 
linhas serão inseridas em uma página até que o espaço total ocupado na página atinja 
aproximadamente 90% do espaço total disponível (ou seja, tamanho da página – header 
da página – PCTFREE). Caso uma atualização faça com que uma linha não caiba mais 
inteiramente em uma página, ela é retirada de sua página original e colocada em uma 
nova página com espaço suficiente para contê-la. Se não houver páginas com tal 
capacidade, a linha é então encadeada. 
Para calcular o espaço físico da tabela inteira no disco é necessário determinar o seu 
número total de linhas e o número de páginas utilizadas. Para determinar o número de 
páginas utilizadas, é necessário saber o tamanho de cada página e o tamanho do espaço 
livre reservado em cada página. Vamos imaginar uma tabela Movimentos com 30000 
linhas, armazenadas em páginas de 2Kb com PCTFREE de 10%, com o cabeçalho de 
cada página ocupando 100 bytes. O cálculo é demonstrado no quadro a seguir. 
 
 
 
 
 
 
 
 
 
 
 
Valores iniciais 
 (Tp) Tamanho da página : 2048 bytes 
 (Cp) Cabeçalho da página : 100 bytes 
 (PctFree) Margem livre % : 10% = 0.1 
 (Tl) Tamanho da linha : 51 bytes (já calculado) 
 (Ql) Qtde linhas na tabela : 30000 linhas 
 
Cálculos 
 (BFree) Margem livre bytes : PctFree * (Tp – Cp) = 195 bytes 
 (Up) Espaço útil na página : Tp – Cp – BFree = 1753 bytes 
 (Qlp) Qtde de linhas / página : Up / Tl = 34 linhas 
 (Qp) Qtde de pág. p/ tabela : Ql / Qlp = 30000 / 34 = 883 pags 
 
Resultado 
 Tamanho total da tabela : Qp * 2048 = 
= 1808384 bytes  1,8 MB 
Aspectos físicos do armazenamento de dados 
Esse valor referem-se apenas ao tamanho requerido pelos dados da tabela e devem ser 
encarados como uma aproximação, uma vez que o valor exato consumido está sujeito a 
diversos outros fatores, tais como política de número de blocos alocados a cada vez pelo 
SGBD, tamanho e tipo dos índices utilizados para a tabela, etc. 
Aspectos físicos do armazenamento de dados 
Índices 
Os índices são recursos de projeto de banco de dados destinados a facilitar tarefas de 
pesquisa de linhas ou de ordenação dos dados de tabelas, como ocorre na emissão de 
relatórios ou de consultas em tela, por exemplo. Um índice é uma estrutura auxiliar que 
apresenta a ordem em que as linhas da tabela aparecem segundo um determinado critério. 
Uma tabela pode possuir vários índices, que oferecem diversas perspectivas distintas de 
seus dados, cada uma delas sob um critério de ordenação diferente, e são mantidos 
atualizados automaticamente pelo sistema. Assim, na tabela original os dados são 
armazenados em uma ordem física qualquer, mas quando acessados através de um índice, 
parecem estar organizados segundo um critério lógico específico. A leitura de uma tabela 
através de um índice envolve então, em princípio, dois tipos de acesso ao disco: um para 
recuperar as páginas do índice onde será feita a pesquisa e outro para trazer para a 
memória a(s) página(s) de dados. A ordenação lógica das tabelas representa um recurso 
praticamente obrigatório na construção de eficientes aplicações comerciais e mecanismos 
de indexação são disponibilizados pelos diferentes SGBDs para que a construção e 
utilização de índices seja simples e rápida. 
A seguir serão apresentados alguns exemplos de índices para ilustrar esse conceito e 
algumas de suas características de utilizaçãoe implementação física. Esses exemplos 
serão baseados na tabela "Contas" do controle bancário simplificado. 
Coluna Tipo / Tamanho Observações 
NrConta CHAR( 4 ) Número da conta 
DtAbertura DATE Data de abertura da conta 
CdAgencia CHAR( 4 ) Código da agência 
VrSaldo NUMBER Saldo atual da conta 
Figura 8: Descrição da estrutura da tabela Contas. 
 Contas 
# NrConta DtAbertura CdAgencia VrSaldo 
1 1025 25/10/95 0060 R$ 2100,00 
2 1021 10/08/95 0040 R$ 568,00 
3 1030 26/11/95 0040 R$ 500,00 
4 1022 01/09/95 0060 R$ 720,00 
5 1028 12/11/95 0050 R$ 1500,00 
6 1023 12/09/95 0040 R$ 150,00 
7 1029 17/11/95 0050 R$ 1050,00 
8 1026 04/11/95 0050 R$ 535,00 
9 1024 23/10/95 0050 R$ 1047,00 
10 1032 12/11/95 0060 
11 1027 10/11/95 0040 R$ 100,00 
12 1031 08/12/95 0060 R$ 50,00 
Figura 9: Tabela Contas com alguns dados de exemplo. 
 
Aspectos físicos do armazenamento de dados 
 
# Expressão Posição 
1 1021 2 
2 1022 4 
3 1023 6 
4 1024 9 
5 1025 1 
6 1026 8 
7 1027 11 
8 1028 5 
9 1029 7 
10 1030 3 
11 1031 12 
12 1032 10 
Figura 10: Representação lógica de um índice por ordem de Número da conta (NrConta). 
O índice possui uma lista com os valores da coluna chave ordenados, juntamente com a 
relação da posição de cada chave na tabela e implementa, portanto, um mapeamento entre 
os valores da chave, ordenados, e os registros físicos correspondentes na tabela, conforme 
mostra a figura a seguir. 
 Índice Tabela 
# Expressão Posição # NrConta DtAbertura CdAgencia VrSaldo 
1 1021 2 1 1025 25/10/95 0060 R$ 2100,00 
2 1022 4 2 1021 10/08/95 0040 R$ 568,00 
3 1023 6 3 1030 26/11/95 0040 R$ 500,00 
4 1024 9 4 1022 01/09/95 0060 R$ 720,00 
5 1025 1 5 1028 12/11/95 0050 R$ 1500,00 
6 1026 8 6 1023 12/09/95 0040 R$ 150,00 
7 1027 11 7 1029 17/11/95 0050 R$ 1050,00 
8 1028 5 8 1026 04/11/95 0050 R$ 535,00 
9 1029 7 9 1024 23/10/95 0050 R$ 1047,00 
10 1030 3 10 1032 12/11/95 0060 
11 1031 12 11 1027 10/11/95 0040 R$ 100,00 
12 1032 10 12 1031 08/12/95 0060 R$ 50,00 
 
 
 
 
 Ordem lógica Ordem física 
 (pela coluna NrConta) (das linhas na tabela) 
Figura 11: Índice como o mapeamento da ordem lógica para os dados físicos da tabela. 
 
Aspectos físicos do armazenamento de dados 
 
# Expressão Posição 
1 R$ 50,00 12 
2 R$ 100,00 11 
3 R$ 150,00 6 
4 R$ 500,00 3 
5 R$ 535,00 8 
6 R$ 568,00 2 
7 R$ 720,00 4 
8 R$ 1047,00 9 
9 R$ 1050,00 7 
10 R$ 1500,00 5 
11 R$ 2100,00 1 
12 10 
Figura 12: Representação lógica de um índice por ordem de Saldo da conta (VrSaldo). 
Além do índice pela chave primária, uma tabela pode necessitar de outros índices, 
chamados de índices secundários. Basicamente são utilizados para chaves estrangeiras e 
colunas utilizadas com muita freqüência como critério de seleção de linhas, tais como 
nomes e alguns códigos. 
# Expressão Posição 
1 0040 2 
2 0040 3 
3 0040 6 
4 0040 11 
5 0050 5 
6 0050 7 
7 0050 8 
8 0050 9 
9 0060 1 
10 0060 4 
11 0060 10 
12 0060 12 
Figura 13: Representação lógica de um índice por ordem de Código da agência (CdAgencia). 
Observe na figura 13 que para as linhas que possuem o mesmo valor para a chave do 
índice o critério de desempate para saber qual deles deve ser acessado primeiro é a ordem 
física na tabela. 
Aspectos físicos do armazenamento de dados 
 
# Expressão Posição 
1 00401021 2 
2 00401023 6 
3 00401027 11 
4 00401030 3 
5 00501024 9 
6 00501026 8 
7 00501028 5 
8 00501029 7 
9 00601022 4 
10 00601025 1 
11 00601031 12 
12 00601032 10 
Figura 14: Representação lógica de um índice por ordem de Código da agência e Número da conta 
(CdAgencia + NrConta) 
Este caso representa um índice cuja expressão chave é formada por mais de uma coluna. 
Esse tipo de chave é chamado de chave composta. No caso, as linhas aparecem por 
ordem de Código da agência e aquelas que possuem mesma agência aparecem por ordem 
de Número da conta. O funcionamento do índice é o mesmo dos exemplos anteriores mas 
neste caso é importante saber que um índice com uma chave composta por CdAgencia + 
NrConta não é equivalente a um índice com uma chave NrConta + CdAgencia. 
As figuras de 10 a 14 procuram oferecer uma adequada visão lógica dos índices, na forma 
de uma espécie de tabela auxiliar que reflete o conteúdo da tabela principal. Não é assim 
entretanto que os índices costumam ser fisicamente implementados nos SGBDs, já que 
existem estruturas de dados mais eficientes para essa finalidade, como as árvores, por 
exemplo. Nos bancos de dados atuais os índices geralmente são construídos por meio de 
árvores B+, que facilitam a tarefa de pesquisa no índice e permitem também um 
tratamento mais prático de operações que envolvem a leitura seqüencial ordenada dos 
dados. Um exemplo de índice B+ para o caso da figura 5 é apresentado a seguir. 
 
 
 
 
 
 
 
Figura 16: Implementação física de um índice por NrConta como uma árvore B+. 
 1026  
 
 1022  1024  
 
 1028  1030  
 
1021 1022 
 
1023 1024 
 
1025 1026 
 
1027 1028 
 
1029 1030 
 
1031 1032 / 
 
Aspectos físicos do armazenamento de dados 
Clusters 
Um cluster (ou agrupamento) de dados é uma estrutura que permite manter fisicamente 
próximos os dados de duas ou mais tabelas que são logicamente ligadas entre si. Isso 
significa procurar manter juntas no mesmo bloco físico do disco as linhas correlacionadas 
dessas tabelas, de tal maneira que quando há uma leitura física do disco, os dados dos 
relacionamentos são trazidos juntos para a memória, pois lê-se sempre a página de dados 
inteira e com isso economiza-se I/O. 
Exemplo: Tabelas Contas e CliContas do controle bancário 
Contas 
NrConta DtAbertura CdAgencia VrSaldo 
1021 10/08/95 0040 R$ 568,00 
1022 01/09/95 0060 R$ 720,00 
1023 12/09/95 0040 R$ 150,00 
1024 23/10/95 0050 R$ 1470,00 
1025 25/10/95 0060 R$ 2100,00 
 
Figura 17: Estrutura lógica das tabelas com alguns dados de exemplo. 
 
NrConta DtAbertura CdAgencia VrSaldo 
 CdCliente Senha 
1021 10/08/95 0040 R$ 568,00 
 00001 ****** 
1022 01/09/95 0060 R$ 720,00 
 00002 ****** 
1023 12/09/95 0040 R$ 150,00 
 00003 ****** 
 00004 ****** 
1024 23/10/95 0050 R$ 1470,00 
 00005 ****** 
1025 25/10/95 0060 R$ 2100,00 
 00006 ****** 
Figura 19: Estrutura física, com a organização dos dados em um cluster para as duas tabelas. 
O agrupamento (ou clusterização) de tabelas como mostrado no exemplo é indicado nas 
situações em que duas ou mais tabelas são sempre lidas em conjunto (em junções, 
portanto) e muito raramente são consultadas em separado, como geralmente ocorre em 
alguns relacionamentos mestre / detalhe envolvendo uma entidade associativa. As 
operações de gravação, por sua vez, ficam um pouco prejudicadas, além do que algum 
espaço adicional em disco e na memória principal acaba sendo necessário para 
administrar esse tipo de estrutura mais complexa. Nem todos os SGBDs suportam o 
cluster de tabelas (como o Oracle suporta), mas a maioria permite o agrupamento de 
índices (como o SQL Server, por exemplo). 
Chaves 
do 
Cluster 
CliContas 
CdCliente NrConta Senha 
00001 1021 ****** 
00002 1022 ****** 
00003 1023 ****** 
00004 1023 ****** 
00005 1024 ****** 
00006 1025 ****** 
 
Aspectos físicos do armazenamento de dados 
Hashing 
Estruturas ou tabelas hash (também chamadas de tabelas de espalhamento) oferecem um 
meio para a localização instantânea de uma chave na tabela, com base apenas em seu 
valor. O espaço físico em disco destinado à tabela é dividido previamente em um número 
fixo de segmentos (também chamados de buckets) numerados e conforme o valor da 
chave, será o segmento em que a linha inteira deverá ser armazenada. Para determinar a 
localização física de uma linha um cálculo deve ser realizado pelo SGBD sobre o valor 
de sua chave, de maneira a obter o número do segmento correspondente. A função que 
mapeia um valor de chave para um segmento é chamada de função hash. A principal 
vantagem dessetipo de estrutura é a rapidez com que um valor é encontrado na tabela, 
mas devido à forma como os dados são gravados no disco, processamentos seqüenciais 
indexados não podem ser beneficiados pelo armazenamento nesse tipo de estrutura. Um 
outro ponto crítico está na definição da função hash, que deve conseguir distribuir as 
chaves de maneira mais uniforme possível, de maneira a não concentrar dados demais em 
certos segmentos em detrimento de outros. Uma discussão detalhada a respeito de tabelas 
de espalhamento e algoritmos para funções hash pode ser encontrada em [ZIVIANI, 
1999] e detalhes sobre a aplicação desse tipo de estrutura em bancos de dados são 
apresentados em [SILBERSCHATZ et al., 1999]. Finalmente, nem todos os SGBDs 
permitem que uma tabela seja organizada diretamente na forma de uma estrutura hash 
como mostrado no exemplo a seguir, mas muitos deles permitem que pelo menos um 
índice por tabela tenha esse tipo de armazenamento. É possível também combinar uma 
estrutura de cluster (de tabela ou de índice) com o uso de mapeamentos hash. 
Exemplo: Tabela Agencias do controle bancário 
Agencias 
CdAgencia NmAgencia EndAgencia TelAgencia 
0040 Praça da Republica Praça da Republica, 200 555-4433 
0050 Centro R 15 de Novembro, 800 555-2211 
0060 Prefeitura Av Sao Paulo, 100 555-6612 
Figura 20: Estrutura lógica da tabela com alguns dados de exemplo. 
Aspectos físicos do armazenamento de dados 
 
Chave Hash CdAgencia NmAgencia EndAgencia TelAgencia 
0 0060 Prefeitura Av Sao Paulo, 100 555-6612 
 
 
 
1 0040 Praça da Republica Praça da Republica, 200 555-4433 
 
 
 
2 0050 Centro R 15 de Novembro, 800 555-2211 
 
 
 
Figura 21: Estrutura hash para a tabela Agencias 
 
 
 
 
 
 
 
 
 
 
 
 
Figura 22: Exemplo de função hash para uso com a estrutura da figura 21. 
 
Func Hash3 ( codigo: cadeia ) : int ; 
Var soma: int; 
 numero: cadeia; 
 posicao: int; 
 contador: int; 
 
Inicio 
 contador  1; 
 soma  0 ; 
 Enquanto contador <= Compr( codigo ) Faça 
 Início 
 numero  Subc( codigo, contador, 1 ) ; 
 soma  soma + CadeiaParaInt( numero ) ; 
 contador  contador + 1 ; 
 Fim ; 
 
 posicao  soma Mod 3 ; 
 Retorne posicao ; 
Fim ; 
Processamento de consultas: visão geral 
 Processamento de consultas 
O processamento de uma consulta de banco de dados é realizado pelo SGBD através de 
inúmeros passos, conforme mostra a figura 1. Geralmente a consulta é formalizada pelo 
usuário através de um dialeto SQL. 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Figura 1: Estrutura geral de processamento de uma consulta 
Compilação: a consulta submetida pelo usuário é analisada em termos de sua estrutura 
geral, operações requeridas e dos objetos utilizados. Caso haja algum problema na 
formação da instrução, uma mensagem de erro é retornada ao usuário e o processamento 
da consulta é cancelado. Consultas corretamente formuladas podem sofrer algum tipo de 
pré-processamento neste momento, como resolução de visões, por exemplo. 
Rescrita da expressão: o comando original referente à consulta é analisado e rescrito 
numa forma mais adequada ao processamento pelo SGBD. 
Compilação 
Rescrita da 
expressão 
Otimização do plano 
de acesso 
Geração do código 
Execução do código 
Instrução SQL 
Catálogo do 
banco de dados Erro 
Dados + Erro Banco de dados 
Processamento de consultas: visão geral 
Otimização do plano de acesso: com base na versão rescrita da consulta e nas 
informações contidas no catálogo do banco de dados, várias estratégias de acesso aos 
dados são produzidas e avaliadas, sendo uma delas escolhida para ser implementada. 
Geração do código: o plano de acesso selecionado é convertido para um código 
executável (ou interpretável ou pseudo-executável) próprio do SGBD. 
Execução do código: as instruções contidas no plano de acesso são executadas pelo 
SGBD, sob o comando do módulo gerente de transações. Os resultados são enviados ao 
usuário, juntamente com um eventual código de erro. 
Compilação: elementos básicos 
O processo de compilação envolve 3 etapas principais, nas quais se procura identificar a 
estrutura do comando, os elementos que são manipulados e a natureza do processamento 
a ser realizado. Essas etapas são tradicionalmente denominadas por análise léxica, análise 
sintática e análise semântica e serão rapidamente descritas a seguir, sendo que uma 
discussão mais aprofundada sobre cada uma pode ser encontrada em qualquer bom livro 
sobre compiladores, como por exemplo Aho et al (1995). 
Análise léxica 
É também chamada de análise linear ou de scanning, e consiste na identificação dos 
tokens do código, ou seja, no isolamento das diversas palavras ou símbolos utilizados na 
construção da instrução SQL original. É com base nesses elementos que toda a análise 
posterior é realizada. 
Análise sintática 
Esta fase é também chamada de análise hierárquica, de análise gramatical ou, ainda, de 
parsing, e tem por objetivo estabelecer a estrutura lógica do processamento envolvido em 
termos de frases gramaticais, geralmente organizadas em árvores. Eventuais erros na 
formação da expressão são também detectados e reportados nesta fase. 
Análise semântica 
A análise semântica verifica problemas de significado nas frases gramaticais produzidas 
na etapa anterior. Os principais aspectos tratados aqui são a validação dos identificadores 
utilizados (nomes de tabelas, colunas, visões, funções, etc) e a verificação de possíveis 
conflitos de tipos de dados nas operações. Para essa tarefa, o compilador precisa utilizar 
as informações contidas no catálogo do banco de dados, além das definições próprias da 
linguagem de consulta suportada. 
Exemplo de trabalho do módulo compilador do SGBD 
Para ilustrar algumas características do processo de compilação de uma consulta, vamos 
considerar que desejamos obter, com base nas tabelas do controle bancário, a informação 
referente a quais contas corrente (e suas respectivas agências) devem pagar pelo menos 
R$ 5,00 de juros e taxas financeiras decorrentes de saldo negativo. O montante devido é 
calculado com base num valor fixo de R$ 3,00 acrescido de juros de 10% do saldo 
devedor. Vamos assumir ainda, por questão de simplicidade, que a consulta é expressa na 
forma da seguinte expressão de álgebra relacional: 
Processamento de consultas: visão geral 
 NrConta, CdAgencia (  VrSaldo < 0 ^ VrSaldo * -0.1 + 3 > 5 ( contas ) ) 
Essa expressão corresponde ao seguinte plano lógico de consulta: 
 
 
 
 
 
 
 
 
 
Figura 2: Plano lógico da consulta 
Análise léxica 
A expressão fornecida ao compilador é decomposta em tokens, alguns dos quais são 
mostrados no quadro a seguir. 
Lexema Token 
 Operador 
NrConta Identificador 
, Símbolo de pontuação 
CdAgencia Identificador 
 Operador 
VrSaldo Identificador 
< Operador 
0 Constante numérica 
contas Identificador 
Análise sintática 
Uma árvore gramatical é criada relacionando os tokens em frases gramaticais com 
sentido. O predicado da restrição da consulta (a expressão lógica VrSaldo < 0 ^ VrSaldo 
* -0.1 + 3 > 5) pode ser expresso conforme mostra a figura 3. Observe que a ordem de 
precedência das operações encontra-se definida nessa representação, onde o 
processamento ocorre a partir das folhas da árvore em direção à sua raiz. 
 NrConta, CdAgencia 
 VrSaldo < 0 ^ VrSaldo * -0.1 + 3 > 5 
contas 
Processamento de consultas: visão geral 
 
 
 
 
 
 
 
Figura 3: Árvore gramatical para um predicado de consulta 
Convém ressaltar que não apenas o predicado é expresso em uma árvore gramatical, mas 
toda a expressão relacional correspondente. 
Análise semântica 
Com base no contexto sugerido pela árvore gramatical gerada anteriormente, o 
compilador determina que o identificador ‘contas’ deve ser uma tabela ou visão à qual o 
usuário precisa ter direitos de acesso e faz essaverificação no catálogo do banco de 
dados. Os identificadores NrConta, CdAgencia e VrSaldo devem ser colunas do objeto 
‘contas’ e o usuário precisa ter direitos de consulta sobre elas. A verificação desses 
requisitos é feita também através de pesquisa ao catálogo do sistema. Por fim, os tipos 
dos dados dos operandos precisam ser compatíveis com as operações indicadas, e para 
isso os valores das constantes são analisados, bem como o tipo definido para a coluna 
VrSaldo no banco de dados. 
Heurísticas do processamento de consultas 
O processamento de uma consulta compilada com êxito envolve a produção de um plano 
de execução ou plano de acesso, que especifica exatamente o que deve ser realizado para 
a obtenção do resultado final. Um plano de execução deve indicar a ordem em que as 
diversas operações relacionais serão executadas, a ordem de acesso às tabelas, os índices 
que serão utilizados, os bloqueios (locks) necessários sobre os dados, as modalidades de 
junção indicadas para cada caso, bem como estratégias adicionais a serem adotadas, 
como recursos de paralelismo e pipelining de operações e o emprego de tabelas 
temporárias, por exemplo. 
Nesta fase, questões de desempenho são analisadas e resolvidas, buscando-se encontrar 
soluções computacionalmente mais econômicas. Para isso, procura-se minimizar o 
volume de dados manipulado e o número de operações de acesso a disco requeridas, o 
que é conseguido através do emprego de algumas regras heurísticas clássicas, tais como 
executar as seleções e projeções antes e rescrever as consultas considerando a 
equivalência entre operações relacionais. 
 ̂
< 
0 VrSaldo 
> 
5 + 
3 
VrSaldo -0.01 
* 
Processamento de consultas: visão geral 
Equivalência entre operações relacionais 
Existe um grande número de relações de equivalência matemática entre operações 
relacionais e, mesmo, entre operações não-relacionais. Algumas dessas relações são 
triviais, como por exemplo (A + B)  (B + A) enquanto que outras são menos óbvias, 
sendo que seu reconhecimento por parte do módulo otimizador do SGBD viabiliza 
interessantes substituições nas consultas originalmente submetidas para processamento, 
que podem proporcionar ganhos significativos de desempenho durante sua execução. 
Algumas dessas equivalências são citadas rapidamente a seguir. 
a. Comutatividade e encadeamento (“cascata”) de restrições 
P1 ^ P2 (r)  P1 (P2 (r))  P2 (P1 (r)) 
b. Associatividade da junção natural 
(r1 |x| r2) |x| r3  r1 |x| (r2 |x| r3) 
c. Comutatividade da junção natural 
r1 |x| r2  r2 |x| r1 
d. Comutatividade da união 
r1  r2  r2  r1 
e. Encadeamento (“cascata”) de projeções 
 L1 ( L2 (...(R))   L1(R) 
f. Comutatividade entre seleções e projeções 
 A ( C (R))   C ( A(R)) 
g. Comutatividade entre seleções e junções 
 C (R |x| S)  ( C(R)) |x| S 
h. Comutatividade entre projeções e junções 
 L(R |x| S)   A(R) |x|  B (S) 
i. Idempotência da união 
r1  r1  r1 
j. Outras equivalências interessantes 
P (r1  r2)  P (r1)  P (r2) 
P (r1  r2)  P (r1)  r2  P (r1)  P (r2) 
(r1  r2)  r3  r1  (r2  r3) 
Processamento de consultas: visão geral 
Exemplo didático de rescrita de uma consulta 
Para ilustrar um caso de rescrita de uma consulta para fins de processamento posterior, 
vamos supor uma instrução solicitando o nome de todos os funcionários do departamento 
chamado ‘ADMINISTRAÇÃO’ que recebem salário superior a $500,00. As tabelas 
disponíveis no banco de dados são: 
funcionarios (NrMatric, NmFunc, DtAdm, Sexo, CdCargo, CdDepto) 
cargos (CdCargo, NmCargo, VrSalario) 
deptos (CdDepto, NmDepto, Ramal) 
 
Para esse banco de dados, a consulta pode ser escrita utilizando o seguinte código SQL: 
SELECT NmFunc 
 FROM cargos c, funcionarios f, deptos d 
 WHERE f.CdCargo = c.CdCargo 
 AND f.CdDepto = d.CdDepto 
 AND NmDepto = 'ADMINISTRACAO' 
 AND VrSalario > 500 ; 
A expressão de álgebra relacional correspondente seria: 
 NmFunc (  f.CdCargo = c.CdCargo ^ ( c (cargos) x  f (funcionarios) x  d (deptos) ) ) 
f.CdDepto = d.CdDepto ^ 
NmDepto = 'ADMINISTRACAO' ^ 
VrSalario > 500 
A preparação dessa consulta envolve a sua validação, verificando possíveis erros de 
sintaxe ou de semântica, por meio do módulo compilador, e sua rescrita, adotando 
algumas heurísticas para a otimização do código e regras de equivalência entre 
expressões, realizadas pelo módulo otimizador. Esse processo de rescrita envolve 
diversas etapas, que podem variar conforme o produto SGBD utilizado, sendo que os 
passos mostrados a seguir foram adaptados a partir de [ELMASRI, 2000] e procuram 
representar de maneira didática os seus aspectos principais. As várias operações 
relacionais a serem realizadas são apresentadas na forma de uma árvore, como é comum 
ocorrer ao se trabalhar com compiladores, de maneira que o processamento requerido 
inicia-se a partir de suas folhas, terminando na raiz. 
Passo 1: Produzir a árvore canônica para a consulta 
 
Existe um conjunto muito vasto de expressões relacionais que podem ser formadas. 
Como já vimos anteriormente, muitas dessas expressões são equivalentes, ou seja, 
representam, a rigor, a mesma consulta. Dentro desse conjunto de todas as expressões 
possíveis existe um subconjunto, bem menor que o primeiro, que contém uma única 
expressão para cada consulta possível. As expressões que fazem parte desse subconjunto 
mínimo de expressões são chamadas de formas canônicas, e são adotadas para simplificar 
o processo de análise do otimizador. Toda consulta submetida ao SGBD é inicialmente 
reduzida à sua forma canônica, expressa em uma linguagem de consulta interna do 
Processamento de consultas: visão geral 
gerenciador e que, para fins deste exemplo, será assumida como sendo a álgebra 
relacional. 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Obs.: Calcular o número total de linhas processado se este plano de execução for 
adotado. Supor que a tabela funcionarios possui 10 linhas, a tabela cargos, 6 linhas e a 
tabela deptos, 4 linhas. 
 
Passo 2: Antecipar as restrições, desmembrando-as 
 
Um dos princípios gerais da otimização de consultas é procurar sempre manipular o 
menor volume de dados possível para produzir os resultados solicitados pela consulta. 
Realizar inicialmente todas as restrições possíveis, antes de qualquer junção ou produto 
cartesiano, reduz o número de linhas a serem manipuladas nas etapas intermediárias, 
sendo que geralmente essa redução é dramática. Em nosso exemplo, algumas restrições 
podem ser realizadas inicialmente, e foram colocadas nos níveis inferiores da árvore. 
 
 NmFunc 
 c cargos 
 f funcionarios 
 d deptos 
 f.CdCargo = c.CdCargo ^ f.CdDepto = d.CdDepto ^ VrSalario > 500 ^ NmDepto = 'ADMINISTRACAO' 
c f 
x d 
x 
Processamento de consultas: visão geral 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Obs.: Calcular o número total de linhas processado se este plano de execução for 
adotado. Supor que a tabela funcionarios possui 10 linhas, a tabela cargos, 6 linhas e a 
tabela deptos, 4 linhas. 
 
 NmFunc 
 c cargos 
 f funcionarios 
 d deptos 
 f.CdDepto = d.CdDepto 
x 
 NmDepto = 'ADMINISTRACAO' 
d 
 f.CdCargo = c.CdCargo 
f 
x 
c 
 VrSalario > 500 
Processamento de consultas: visão geral 
Passo 3: Colocar a restrição mais restritiva em primeiro lugar 
 
Em uma situação normal, espera-se que haja um número maior de linhas referentes a 
cargos com VrSalario > 500 (que é uma inigualdade) do que linhas de departamentos 
onde o valor da coluna NmDepto seja igual à constante ‘ADMINISTRACAO’. Inclusive, 
é de se supor que essa coluna seja única, não permitindo valores duplicados. Com isso, 
qualquer comparação de igualdade sobre essa coluna deve retornar no máximo uma linha. 
Portanto, restrições como essa, se forem executadas antes das outras, vão gerar umnúmero menor de combinações com as outras tabelas nas etapas seguintes. 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 NmFunc 
 c cargos 
 f funcionarios 
 d deptos 
 f.CdCargo = c.CdCargo 
x 
c 
 VrSalario > 500  f.CdDepto = d.CdDepto 
 NmDepto = 'ADMINISTRACAO' 
d 
f 
x 
Processamento de consultas: visão geral 
 
Obs.: Calcular o número total de linhas processado se este plano de execução for 
adotado. Supor que a tabela funcionarios possui 10 linhas, a tabela cargos, 6 linhas e a 
tabela deptos, 4 linhas. 
 
Passo 4: Introduzir junções quando apropriado 
 
Combinações de produtos cartesianos com restrições correspondentes a equações de 
junção devem ser substituídas por operações de junção, que costumam ter 
implementações internas mais eficientes. 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 NmFunc 
 c cargos 
 f funcionarios 
 d deptos 
|x| f.CdCargo = c.CdCargo 
c 
 VrSalario > 500 
 NmDepto = 'ADMINISTRACAO' 
d 
f 
|x| f.CdDepto = d.CdDepto 
Processamento de consultas: visão geral 
Passo 5: Antecipar as projeções 
 
Assim como antecipar restrições é interessante para diminuir a quantidade de linhas 
processadas, antecipar projeções também contribui para reduzir o volume total de dados 
manipulados já que descarta colunas que não são usadas no processo. Observe que as 
projeções intermediárias contêm tanto as colunas necessárias à projeção final como 
também os atributos de relacionamento necessários às junções subseqüentes. 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Obs.: Calcular o número total de linhas processado se este plano de execução for 
adotado. Supor que a tabela funcionarios possui 10 linhas, a tabela cargos, 6 linhas e a 
tabela deptos, 4 linhas. 
 NmFunc 
 c cargos 
 f funcionarios 
 d deptos 
|x| f.CdCargo = c.CdCargo 
c 
 VrSalario > 500 
 c.CdCargo |x| f.CdDepto = d.CdDepto 
 NmDepto = 'ADMINISTRACAO' 
d 
 d.CdDepto 
f 
 NmFunc, f.CdCargo, f.CdDepto 
Geração de planos de execução 
Geração de planos de execução 
Algoritmos para a classificação (ordenação) de dados 
Classificação interna: é aquela em que todos os dados estão na memória principal 
(memória RAM). Existem diversos métodos clássicos para esse fim, como por exemplo, 
seleção direta, bubblesort ou quicksort, que são descritos e avaliados na literatura sobre 
lógica de programação e estruturas de dados, como por exemplo [ZIVIANI, 1999]. 
Classificação externa: é a ordenação de dados que encontram-se armazenados em disco e 
não podem ser carregados em sua totalidade para a memória principal, como 
freqüentemente ocorre nos bancos de dados comerciais, onde o volume de dados em 
determinadas tabelas pode ser muito grande. 
Uma abordagem bastante comum para classificação interna é a chamada Merge-Sort 
[GARCIA-MOLINA et al., 2001; SILBERSCHATZ et al., 1999], que procura dividir o 
conjunto de dados a ser ordenado em partes que caibam na memória principal, ordena 
cada parte através de um método de classificação interna qualquer (geralmente o 
QuickSort) e depois combina (merge) os diversos subconjuntos ordenados de maneira a 
produzir um resultado final totalmente classificado. 
m  CalcSegmentos( R ) ; 
Para i de 1 até m Faça 
Início 
 T  LeSegmento( R, i ) ; 
 OrdenaSegmento( T, Xi ) ; 
Fim ; 
 
Para i de 1 até m Faça 
 Bi  LeBlocoTemp( Xi ) ; 
 
Y  { } ; 
Para j de 1 até n Faça 
Início 
 r  ExtraiMenor( B1 .. Bm ) ; 
Y  Y + r ; 
Fim ; 
 
Observações: 
a) A subrotina CalcSegmentos( <conjunto de dados> ) calcula 
quantos subconjuntos devem ser gerados para o conjunto 
informado, de maneira que cada subconjunto caiba na memória 
disponível no sistema. 
Geração de planos de execução 
b) A subrotina LeSegmento( <conjunto de dados>, <número> ) faz a 
leitura de todo o conteúdo do segmento do conjunto de dados cujo 
número é informado no segundo parâmetro. 
c) A subrotina OrdenaSegmento( <segmento>, <arq. temporário> ) 
aplica um método de classificação interna sobre o segmento e 
grava seus dados ordenados no arquivo temporário indicado. 
d) A subrotina LeBlocoTemp( <arq. temporário> ) retorna um ou 
mais blocos de dados do arquivo temporário indicado e o armazena 
em um buffer de memória específico. 
e) A subrotina ExtraiMenor( <lista de buffers> ) verifica qual é a 
linha de menor valor para a expressão chave de ordenação entre os 
m buffers presentes na memória, elimina essa linha da memória e 
devolve seu valor para a rotina que a chamou. Se o buffer do qual a 
linha foi extraída ficar vazio, uma nova chamada à subrotina 
LeBlocoTemp é realizada para ele. 
f) A operação + indica uma união onde elementos (no caso linhas) 
repetidos são aceitos no resultado final. 
Algoritmos para o processamento de junções 
Existem diversas abordagens para o processamento de junções, sendo que cada uma 
comporta inúmeras variações visando melhorias de desempenho para o tratamento de 
situações específicas. As principais abordagens são denominadas nested loops (laços 
aninhados), merge scan (junção por busca e intercalação) e hash join (junção hash). 
Nested loops: é a abordagem mais simples e de propósito geral, que apresenta um alto 
custo computacional, muitas vezes sendo chamada de método da força bruta [DATE, 
2000]. Uma relação é processada no looping mais externo e a outra no looping mais 
interno, podendo ocorrer ou não o uso de um índice, conforme mostram os algoritmos a 
seguir. 
Sem índice 
T  { } ; 
Para i de 1 até n Faça 
Início 
r  Ri ; 
Para j de 1 até m Faça 
Início 
s  Sj ; 
Se s.ExpChave = r.ExpChave Então 
T  T  ( s * r ) ; 
Fim ; 
Fim ; 
Geração de planos de execução 
Observações: 
a) <var>  <tabela>j indica que o conteúdo da linha localizada na posição j 
da tabela é lido para a variável de memória. 
b) Número de linhas de tabela lidas com esta abordagem: n + n * m. 
 
Com índice 
T  { } ; 
Para i de 1 até n Faça 
Início 
r  Ri ; 
j  Pesq( ÍndiceDeS, r.ExpChave ) ; 
s  Sj ; 
Enquanto s.ExpChave = r.ExpChave Faça 
Início 
T  T  ( s * r ) ; 
j  Prox( ÍndiceDeS ) ; 
s  Sj ; 
Fim ; 
Fim ; 
Observações: 
a) <var>  <tabela>j indica que o conteúdo da linha localizada na posição j 
da tabela é lido para a variável de memória. 
b) A subrotina Pesq( <índice>, <chave> ) faz a busca de um valor chave no 
índice mencionado no primeiro parâmetro, retornando a posição da 
primeira linha com esse valor na tabela. 
c) A subrotina Prox( <conjunto de dados> ) faz a leitura seqüencial da 
próxima linha de uma tabela ou índice. 
d) Número de linhas de tabela lidas com esta abordagem: n + m. 
Merge scan: implementa um balanced line entre as duas relações a serem combinadas, 
que devem estar ordenadas de acordo com os atributos utilizados na expressão de junção. 
É eficiente em situações em que não existem índices adequados para a junção e em que o 
otimizador estima que o número de linhas a serem recuperadas nas duas tabelas é grande. 
Geração de planos de execução 
T  { } ; 
r  R1 ; 
s  S1 ; 
Enquanto r  Null ^ s  Null Faça 
Início 
Chave  Maior( r.ExpChave, s.ExpChave ) ; 
Enquanto s.ExpChave < Chave Faça 
s  Prox( S ) ; 
Enquanto r.ExpChave < Chave Faça 
r  Prox( R ) ; 
j  Pos( r, R ) ; 
Enquanto s.ExpChave = Chave Faça 
Início 
r  Rj ; 
Enquanto r.ExpChave = Chave Faça 
Início 
T  T  ( s * r ) ; 
r  Prox( R ) ; 
Fim ; 
s  Prox( S ) ; 
Fim ; 
Fim ; 
Observações: 
a) <var>  <tabela>j indica que o conteúdo da linha localizada na 
posição j da tabela é lido para a variável de memória. 
b) A subrotina Maior( <expressão1>, <expressão2> ) devolve 
<expressão1> se esta for maior ou igual a <expressão2> ou, caso 
<expressão2> seja maior que <expressão1>, devolve o valor de 
<expressão2>. 
c) A subrotina Pos( <tupla>, <conjunto de dados> ) devolve a 
posição que a tupla informada ocupa no conjunto dedados. 
d) A subrotina Prox( <conjunto de dados> ) faz a leitura seqüencial 
da próxima linha de uma tabela ou índice. 
 
Geração de planos de execução 
Hash join: armazena uma das tabelas na memória principal adotando uma estrutura hash 
com base nos valores de sua chave. Em seguida, gera os resultados fazendo a leitura 
simples (via índice ou não) da tabela remanescente e determinando as correspondências 
com a primeira tabela por meio da aplicação da função hash sobre a coluna chave do 
relacionamento. É uma solução interessante para situações em que uma das tabelas cabe 
totalmente na memória principal. 
b  CalcBuckets( R ) ; 
Para i de 1 até b Faça 
 Bj  { } ; 
 
Para i de 1 até n Faça 
Início 
r  Ri ; 
 j  Hash( r ) ; 
 Bj  Bj  r ; 
Fim ; 
 
T  { } ; 
Para i de 1 até m Faça 
Início 
s  Si ; 
j  Hash( s ) ; 
r  PesqBucket( s, Bj ) ; 
T  T  ( s * r ) ; 
Fim ; 
Observações: 
a) A subrotina CalcBuckets( <tabela> ) determina o número de 
buckets necessários para armazenar o conteúdo da tabela em uma 
estrutura hash na memória e seleciona uma função hash para fazer 
o mapeamento correspondente. 
b) <var>  <tabela>j indica que o conteúdo da linha localizada na 
posição j da tabela é lido para a variável de memória. 
c) A subrotina Hash( <tupla> ) recebe uma tupla e calcula o número 
do bucket correspondente à chave dessa tupla. 
d) A subrotina PesqBucket( <tupla>, <bucket> ) pesquisa e retorna 
uma tupla dentro de um bucket que possua correspondência com a 
chave da tupla fornecida no primeiro parâmetro. 
 
Geração de planos de execução 
Elementos que afetam a eficiência de um plano de execução 
 volume de dados a serem processados 
 algoritmos disponíveis 
 existência de estatísticas atualizadas 
 organização física dos dados 
 tamanho de página 
 existência de índices, clusters, hashing 
 
Estratégia de seleção de planos baseada em regras 
Nesta abordagem, o otimizador não faz uso de estatísticas, e procura adotar uma solução 
baseada em heurísticas e no custo presumido para o conjunto de operações previsto no 
plano de execução. Em resumo, esta modalidade envolve as seguintes etapas: 
a) Vários planos de execução são gerados 
b) Para cada plano é atribuído um grau de dificuldade, com base na tabela de custos 
estimados dos caminhos de acesso 
c) O plano com menor grau de dificuldade é adotado. 
O quadro a seguir apresenta um ranking dos caminhos de acesso no Oracle em ordem 
crescente de custo presumido, onde quanto maior o grau do caminho de acesso, maior o 
custo estimado para o processamento. Todo o conjunto de regras adotado pelo otimizador 
baseia-se nesse ranking, uma vez que nessa modalidade não se faz uso de estatísticas 
sobre o estado do banco de dados no momento da consulta. 
Geração de planos de execução 
 
Grau Caminho de acesso e exemplos 
1 Uma linha por RowId (“single row by RowId”) 
 
SELECT * 
 FROM Clientes 
 WHERE RowID = ‘00003894024033750001’ 
2 Uma linha por junção no cluster (“single row by cluster join”) 
 
SELECT * 
 FROM Contas c, CliContas cc 
 WHERE c.NrConta = cc.NrConta AND c.NrConta = '1027' 
3 Uma linha por chave hash com coluna única ou chave primária (“Single row 
by hash cluster key with unique or primary key”) 
 
SELECT * 
 FROM Agencias 
 WHERE CdAgencia = ‘0060’ 
4 Uma linha por chave única ou chave primária (“single row by unique or 
primary key”) 
 
SELECT * 
 FROM Clientes 
 WHERE CdCliente = ‘00001’ 
5 Várias linhas por junção em cluster (“cluster join”) 
 
SELECT * 
 FROM Contas c, CliContas cc 
 WHERE c.NrConta = cc.NrConta 
6 Várias linhas através de chave hash (“hash cluster key”) 
 
SELECT * 
 FROM Gerentes 
 WHERE CdAgencia = '0040' ; 
7 Várias linhas, pela chave do cluster indexado (“indexed cluster key”). 
 
SELECT * 
 FROM CliContas 
 WHERE NrConta = '1021' ; 
8 Várias linhas com chave composta (“composite key”) 
 
SELECT * 
 FROM Gerentes 
 WHERE TpGerente = 'C' AND NmGerente LIKE 'J%' ; 
9 Índice de chave não composta (“single column indexes”) 
 
SELECT * 
 FROM Contas 
 WHERE CdAgencia = ‘0060’ 
 
Geração de planos de execução 
 
Grau Caminho de acesso e exemplos 
10 Busca de faixa limitada de valores em coluna indexada (“bounded range 
search on indexed columns”) 
 
SELECT * 
 FROM Movimentos 
 WHERE DtMov BETWEEN ‘01/01/99’ AND ‘31/12/99’ ; 
11 Busca de faixa não limitada em coluna não indexada (“unbounded range 
search on indexed columns”) 
 
SELECT * 
 FROM Movimentos 
 WHERE DtMov > ‘01/01/99’ ; 
12 Junção sort merge (“sort merge join”). Para fins didáticos, é conveniente que 
não haja índices para as colunas da junção. 
 
SELECT NmGerente 
 FROM Gerentes, Clientes 
 WHERE NmGerente = NmCliente ; 
13 Valores máximo ou mínimo em coluna indexada (“Max or min of indexed 
columns”) 
 
SELECT MIN( DtMov ) 
 FROM Movimentos ; 
14 Order by em coluna indexada (“order by on indexed columns”) 
 
SELECT * 
 FROM Movimentos 
 ORDER BY NrConta ; 
15 Acesso seqüencial à tabela ( “full table scan”) 
 
SELECT * 
 FROM Movimentos 
 WHERE VrMov < 50 AND TpMov = ‘C’ ; 
 
Estratégia de seleção de planos baseada em custos 
 conceito e computação de custos 
 estatísticas úteis para a otimização de consultas 
- número de linhas da tabela 
- tamanho da linha 
- número de páginas ocupadas pela tabela 
- número de níveis do índice 
- número de valores distintos para uma coluna 
Geração de planos de execução 
- maior e menor valor para uma coluna 
- seletividade da coluna 
Geração de planos de execução 
Prática de laboratório 
Instruções para atualização de estatísticas no catálogo do banco de dados 
 
Oracle: 
Estatísticas principais ficam armazenadas nas visões ALL_TABLES, 
ALL_TAB_COLUMNS E ALL_INDEXES do catálogo. 
 
ANALYZE TABLE <nome_tabela> COMPUTE STATISTICS ; 
ANALYZE TABLE <nome_tabela> ESTIMATE STATISTICS ; 
ANALYZE TABLE <nome_tabela> DELETE STATISTICS ; 
ANALYZE INDEX <nome_índice> COMPUTE STATISTICS ; 
 
MS-SQL Server: 
As estatísticas são atualizadas automaticamente nas versões mais recentes do SGBD. 
 
UPDATE STATISTICS <nome_tabela> 
UPDATE STATISTICS <nome_tabela> WITH FULLSCAN, ALL 
UPDATE STATISTICS <nome_índice> 
 
DB2: 
RUNSTATS ON TABLE <nome_tabela> WITH DISTRIBUTION AND DETAILED 
INDEX 
 
Utilização do recurso Explain Plan no Oracle 
A instrução Explain Plan permite visualizar o plano de acesso escolhido pelo otimizador 
para processar uma consulta. Os detalhes do plano são armazenados em uma tabela 
chamada Plan_Table, que deve ser criada por meio do script UtlXplan.sql, que 
geralmente fica armazenado na pasta %ORACLE_HOME%\Rdbms\Admin. 
Para analizar o plano de uma consulta, emite-se o comando Explain Plan, conforme a 
sintaxe a seguir: 
 EXPLAIN PLAN 
 SET STATEMENT_ID = <Rótulo para consulta> 
 INTO PLAN_TABLE 
 FOR 
 <instrução SQL> ; 
O rótulo da consulta é um texto livre de até 30 caracteres que será utilizado para 
identificá- la posteriormente para visualizar o plano de acesso. 
Exemplo: 
EXPLAIN PLAN 
SET STATEMENT_ID = 'MovData' 
INTO PLAN_TABLE 
FOR 
 SELECT * FROM Movimentos WHERE DtMov > '01/01/99' ; 
Geração de planos de execução 
Com isso, o otimizador definirá um plano de acesso e o registrará na plan table, 
indicando que ele se refere a uma consulta chamada ‘MovData’. Para cada etapa do plano 
é inserida uma linha nessa tabela de resultados e para visualizarmos esse conteúdo é 
necessário fazer um SELECT sobre a plan table, como no exemplo a seguir: 
SELECT LPAD( ' ', 2 * Level ) || Operation 
 || ' ' || Options || ' ' || Object_Name || ' ' 
 || DECODE( Optimizer, NULL, ' ', Optimizer ) || ' ' 
 || DECODE( Cost, NULL, ' ', ' Custo = ' || Cost 
 || ' linhas esperadas = ' || Cardinality ) Plano 
FROM Plan_Table 
START WITH ID = 0 AND Statement_ID = 'MOVDATA' 
CONNECT BY PRIOR ID = Parent_ID AND Statement_ID = 'MOVDATA'; 
Observe que o valor para a coluna Statement_ID é aquele rótulo informado na instrução 
Explain Plan, e que esse valor é armazenado em maiúsculas na plan table. O resultado é 
exibido de maneira a indicar as operações mais externas próximas à margem esquerda da 
tela e as mais internas, deslocadas para a direita, conforme mostra o exemplo: 
PLANO 
----------------------------------------------------------------------- 
 SELECT STATEMENT CHOOSE 
 NESTED LOOPS 
 TABLE ACCESS BY ROWID CONTAS 
 INDEX UNIQUE SCAN CO_PK_NRCONTA 
 TABLE ACCESS CLUSTER CLICONTAS 
Esse resultado indica o algoritmo de junção adotado (Nested loops, no caso), a ordem e a 
forma pela qual as tabelas são acessadas e os índices que são utilizados, permitindo ao 
analista verificar se a estratégia de processamento adotada corresponde ao esperado. Em 
resumo, o processo de análise pode ser resumido graficamente conforme mostra a figura 
a seguir. 
Comando 
Explain Plan 
Geração do 
Plano de 
Execução Instrução 
SQL DML + 
Statement_Id 
 
Catálogo do 
Banco de Dados 
Índices, 
Tabelas, 
Chaves 
 
Plan_Table 
Visualização 
Plan_Table 
Resultado da 
Análise + 
Statement_ID 
Análise + 
Statement_ID 
Level 
Statement Execution Plan 
Optimizer 
Relatório da 
Análise 
Geração de planos de execução 
Fornecendo dicas ao otimizador 
Oracle: 
Forçando a utilização de um índice: 
SELECT /*+ INDEX( movimentos mv_ix_dtmov ) */ NrMov, VrMov, TpMov 
 FROM Movimentos 
 WHERE NrConta = '1021' AND DtMov = '01/09/96' 
 ORDER BY DtMov ; 
Forçando a leitura direta da tabela: 
SELECT /*+ FULL(Clicontas) */ * 
 FROM CliContas 
 WHERE NrConta = '1021' ; 
 
Interbase: 
Forçando a utilização de um índice: 
SELECT NrMov, VrMov, TpMov 
 FROM Movimentos 
 WHERE NrConta = ‘1021’ AND DtMov = ‘01/09/96’ 
 ORDER BY DtMov ; PLAN( Movimentos INDEX( MV_IX_DTMOV ) ) 
 
MS-SQL Server: 
Forçando a utilização de um índice: 
SELECT NrMov, VrMov, TpMov 
 FROM Movimentos ( index = mv_ix_dtmov ) 
 WHERE NrConta = ‘1021’ AND DtMov = ‘01/09/96’ 
 ORDER BY DtMov 
 
 
 
 
Referências bibliográficas 
AHO, Alfred V.; SETHI, Ravi & ULLMAN, Jeffrey D. Compiladores: Princípios, Técnicas 
e Ferramentas. Rio de Janeiro: Guanabara Koogan, 1995. 344 p. 
BROBOWSKI, Steven M. Dominando o Oracle 7. São Paulo: Makron Books, 1995. 
COREY, Michael; ABBEY, Michael; ABRAMSON, Ian & TAUB, Ben. Oracle 8i Data 
Warehouse. Rio de Janeiro: Campus, 2001. 817 p. 
DATE, C.J. 2000. Introdução a Sistemas de Bancos de Dados. 3a Ed. Rio de Janeiro: 
Campus. 873 p. 
DATE, C.J. Introdução a sistemas de bancos de dados. Rio de Janeiro: Campus, 1991. 674 
p. 
ELMASRI, Ramez e NAVATHE, Shamkant B. 2000. Fundalmentals of database systems. 
Reading: Addison Wesley. 955 p. 
GARCIA-MOLINA, Hector; ULLMAN, Jeffrey D. e WIDOM, Jennifer. 2001. 
Implementação de sistemas de bancos de dados. Rio de Janeiro: Campus. 685 p. 
HIPSLEY, Paul. Developing Client / Server Applications with Oracle Developer / 2000. 
Indianapolis: SAMS Publishing, 1996. 
KORTH, H.F. & SILBERSCHATZ A. Sistema de Banco de Dados. 2ª Ed. Rev. São Paulo: 
Makron Books, 1995. 
LONEY, Kevin & THERIAULT, Marlene. Oracle 8i: O manual do DBA. Rio de Janeiro: 
Campus, 2000, 972 p. 
MELO, Rubens N. et al. Banco de Dados em Aplicações Cliente-Servidor. Rio de Janeiro: 
Livraria e Editora InfoBook, 1997. 
SILBERSCHATZ, Avi; KORTH, Henry; SUDARSHAN S. Sistema de Banco de Dados. 3a 
ed. São Paulo: Makron Books, 1999. 778 p. 
SPENIK, Mark & SLEDGE, Orryn. Microsoft SQL ServerTM 2000 DBA: Guia de 
sobrevivência. Rio de Janeiro: Campus, 2001, 771 p. 
TANENBAUM, Andrew S. Sistemas operacionais modernos. Rio de Janeiro: Prentice-Hall 
do Brasil, 1995, 493 p. 
Tuning de Consultas. Apostila do curso empresarial 2, ministrado durante o XVI SBBD da 
SBC em outubro de 2001 no IME, Rio de Janeiro, pelo professor Paulo Guerra. 
WHALEN, Edward. Oracle: Performance Tuning and Optimization. Indianapolis: SAMS 
Publishing, 1996. 
YONG, Chu Shao. Banco de Dados: Organização, sistemas e administração. São Paulo: 
Atlas, 1983. 398 p. 
ZIVIANI, Nivio. Projeto de algoritmos com implementações em Pascal e C. 4a Ed. São 
Paulo: Pioneira, 1999, 267 p.