12.11.2014 Views

Otimização de Consultas - INF-Unioeste

Otimização de Consultas - INF-Unioeste

Otimização de Consultas - INF-Unioeste

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

Banco <strong>de</strong> Dados I<br />

2007<br />

Módulo VI: Processamento e<br />

<strong>Otimização</strong> <strong>de</strong> <strong>Consultas</strong><br />

(Aulas 1-5)<br />

Clodis Boscarioli


Agenda:<br />

O Processador <strong>de</strong> <strong>Consultas</strong>:<br />

Conceitos Principais.<br />

Algoritmos usados para implementar operações<br />

algébricas;<br />

<strong>Otimização</strong> Baseada em Custo;<br />

<strong>Otimização</strong> Heurística;<br />

Comentários sobre otimização no PostgreSQL.


Visão Geral<br />

<strong>de</strong> um SGBD<br />

Usuários<br />

navegantes<br />

Interface com<br />

aplicações<br />

Programadores<br />

<strong>de</strong> aplicações<br />

Programas <strong>de</strong><br />

aplicações<br />

Usuários<br />

sofisticados<br />

<strong>Consultas</strong><br />

(queries)<br />

Administradores<br />

<strong>de</strong> BD<br />

Esquema <strong>de</strong><br />

Banco <strong>de</strong> Dados<br />

Usuários<br />

Processador<br />

<strong>de</strong> consultas<br />

Programas <strong>de</strong><br />

aplicações em<br />

código objeto<br />

Pré-compilador<br />

<strong>de</strong> comandos<br />

DML<br />

Compilador<br />

DML<br />

Interpretador<br />

DDL<br />

SGBD<br />

Componentes <strong>de</strong> execução<br />

<strong>de</strong> consultas<br />

Gerenciador<br />

<strong>de</strong> memória<br />

Gerenciador<br />

<strong>de</strong> transações<br />

Gerenciador<br />

<strong>de</strong> buffer<br />

Gerenciador<br />

<strong>de</strong> arquivos<br />

Armazenamento<br />

em disco<br />

Arquivos <strong>de</strong><br />

dados<br />

Índices<br />

Dados<br />

estatísticos<br />

Dicionário<br />

<strong>de</strong> dados<br />

BD


Processamento <strong>de</strong> <strong>Consultas</strong><br />

Processar consultas envolve:<br />

Traduzir consultas expressas em linguagens<br />

<strong>de</strong> alto nível (como SQL) em expressões que<br />

po<strong>de</strong>m ser implementadas no nível físico do<br />

sistema <strong>de</strong> banco <strong>de</strong> dados (nível <strong>de</strong> tabelas);<br />

Otimizar a expressão <strong>de</strong>stas consultas;<br />

Avaliar a base <strong>de</strong> dados <strong>de</strong> acordo com as<br />

diretrizes da consulta, para fornecer o<br />

resultado.


Processamento <strong>de</strong> <strong>Consultas</strong><br />

<br />

<br />

Consulta SQL<br />

É a<strong>de</strong>quada para uso humano;<br />

Não a<strong>de</strong>quada ao processamento pelo SGBD:<br />

Não <strong>de</strong>screve uma seqüência <strong>de</strong> passos<br />

(procedimento) a ser seguida;<br />

Não <strong>de</strong>screve uma estratégia eficiente para a<br />

implementação <strong>de</strong> cada passo no que tange o<br />

acesso em nível físico (arquivos do BD).<br />

Cabe ao SGBD <strong>de</strong>ve se preocupar com este<br />

processamento módulo Processador <strong>de</strong> <strong>Consultas</strong>.


Módulo Processador <strong>de</strong> <strong>Consultas</strong><br />

<br />

<br />

Objetivo: <strong>Otimização</strong> do processamento <strong>de</strong> uma<br />

consulta<br />

Tradução, transformação e geração <strong>de</strong> uma estratégia<br />

(plano) <strong>de</strong> execução;<br />

Estratégia <strong>de</strong> acesso:<br />

Consi<strong>de</strong>ra algoritmos pre<strong>de</strong>finidos para implementação <strong>de</strong><br />

passos do processamento e estimativas sobre os dados.<br />

O esforço é valido, pois quase sempre<br />

T x


Passos no Processamento <strong>de</strong> <strong>Consultas</strong><br />

Consulta<br />

Analisador<br />

sintático<br />

e tradutor<br />

Expressão<br />

algébrica<br />

relacional<br />

Otimizador<br />

Saída da<br />

consulta<br />

Avaliador<br />

Plano <strong>de</strong><br />

execução<br />

Dados<br />

Metadados


Passos no Processamento <strong>de</strong> <strong>Consultas</strong><br />

Consulta<br />

Analisador<br />

sintático<br />

e tradutor<br />

Expressão<br />

algébrica<br />

relacional<br />

Otimizador<br />

• Análise léxica<br />

- cláusulas<br />

Saída<br />

SQL<br />

da<br />

e nomes válidos.<br />

Avaliador<br />

• Análise sintática consulta<br />

- validação da gramática.<br />

• Análise semântica<br />

- nomes usados <strong>de</strong> acordo com a estrutura<br />

do esquema.<br />

Dados<br />

• Conversão para uma árvore algébrica<br />

da consulta<br />

Plano <strong>de</strong><br />

execução<br />

Metadados


Passos no Processamento <strong>de</strong> <strong>Consultas</strong><br />

Consulta<br />

Analisador<br />

sintático<br />

e tradutor<br />

Expressão<br />

algébrica<br />

relacional<br />

Otimizador<br />

• Definição <strong>de</strong> uma árvore <strong>de</strong><br />

consulta equivalente<br />

Saída da<br />

consulta<br />

Avaliador<br />

- chega ao mesmo resultado<br />

- processa <strong>de</strong> forma mais<br />

eficiente<br />

• Fase chamada <strong>de</strong><br />

<strong>Otimização</strong> Algébrica<br />

Dados<br />

Plano <strong>de</strong><br />

execução<br />

Metadados


Passos no Processamento <strong>de</strong> <strong>Consultas</strong><br />

Análise <strong>de</strong> alternativas <strong>de</strong> <strong>de</strong>finição <strong>de</strong><br />

estratégias <strong>de</strong> acesso<br />

Consulta<br />

- escolha <strong>de</strong> algoritmos para<br />

Analisador<br />

sintático<br />

e tradutor<br />

implementação <strong>de</strong> operações<br />

- existência <strong>de</strong> índices<br />

- estimativas sobre os dados<br />

(tamanho <strong>de</strong> tabelas, seletivida<strong>de</strong>, ...)<br />

Expressão<br />

algébrica<br />

relacional<br />

Otimizador<br />

Saída da<br />

consulta<br />

Avaliador<br />

Plano <strong>de</strong><br />

execução<br />

Dados<br />

Metadados


Passos no Processamento <strong>de</strong> <strong>Consultas</strong><br />

Consulta<br />

Analisador<br />

sintático<br />

e tradutor<br />

Expressão<br />

algébrica<br />

relacional<br />

FOCO:<br />

OTIMIZADOR DE<br />

CONSULTA<br />

Otimizador<br />

Saída da<br />

consulta<br />

Avaliador<br />

Plano <strong>de</strong><br />

execução<br />

Dados<br />

Metadados


Exemplo Introdutório<br />

<br />

Suponha a consulta:<br />

select saldo<br />

from conta<br />

where saldo < 2500;<br />

<br />

Esta po<strong>de</strong> ser traduzida nas duas expressões algébricas<br />

relacionais diferentes:<br />

σ<br />

saldo < 2500 (π saldo (conta))<br />

π saldo (σ saldo < 2500(conta))


Exemplo Introdutório<br />

<br />

<br />

Além <strong>de</strong>sta variação, é possível executar cada operação<br />

algébrica relacional usando um entre diversos<br />

algoritmos diferentes. Por exemplo:<br />

Para executar a seleção, po<strong>de</strong>mos procurar em todas<br />

as tuplas <strong>de</strong> conta a fim <strong>de</strong> encontrar as tuplas com<br />

saldo menor 2.500.<br />

Se um índice árvore-B+ estiver disponível no atributo<br />

saldo, po<strong>de</strong>mos usar o índice em vez <strong>de</strong> localizar as<br />

tuplas.<br />

É necessário prover as expressões algébricas <strong>de</strong><br />

anotações que permitam especificar como serão<br />

avaliadas.


Exemplo Introdutório<br />

Uma operação algébrica relacional anotada com<br />

instruções sobre como ser avaliada é chamada<br />

<strong>de</strong> avaliação primitiva.<br />

Vária avaliações primitivas po<strong>de</strong>m ser<br />

agrupadas em pipeline, e executadas em<br />

paralelo.<br />

Uma seqüência <strong>de</strong> operações primitivas é um<br />

plano <strong>de</strong> execução <strong>de</strong> consulta ou plano <strong>de</strong><br />

avaliação <strong>de</strong> consulta.


Exemplo Introdutório<br />

π saldo<br />

σ saldo < 2500 (use índice 1)<br />

conta<br />

<br />

Uma vez escolhido o plano <strong>de</strong> consulta, a consulta é<br />

avaliada com aquele plano e o resultado da consulta é<br />

produzido


<strong>Otimização</strong> <strong>de</strong> <strong>Consultas</strong><br />

<br />

Existem 2 técnicas básicas para otimização <strong>de</strong><br />

consultas:<br />

As baseadas em heurísticas para a or<strong>de</strong>nação <strong>de</strong><br />

acesso ao banco <strong>de</strong> dados, que participarão da<br />

estratégia <strong>de</strong> acesso;<br />

e as que estimam sistematicamente o custo <strong>de</strong><br />

estratégias <strong>de</strong> execução diferentes e escolhem o<br />

plano <strong>de</strong> execução com o menor custo estimado.


Catálogo <strong>de</strong> Informações para Estimativa <strong>de</strong><br />

Custo<br />

n r : é o número <strong>de</strong> tuplas na relação r;<br />

b r : é o número <strong>de</strong> blocos que contêm tuplas da relação r;<br />

s r : é o tamanho em bytes <strong>de</strong> uma tupla da relação r;<br />

<br />

<br />

f r : é o fator <strong>de</strong> bloco da relação r, ou seja, o número <strong>de</strong><br />

tuplas da relação r que cabe em um bloco;<br />

V(A,r): é o número <strong>de</strong> valores distintos que aparecem na<br />

relação r para o atributo A. Esse valor é igual ao<br />

tamanho (em número <strong>de</strong> tuplas) <strong>de</strong> π A (r). Se A é uma<br />

chave para a relação r, V(A,r) é n r .


Catálogo <strong>de</strong> Informações para Estimativa <strong>de</strong><br />

Custo<br />

<br />

SC(A,r): é a cardinalida<strong>de</strong> <strong>de</strong> seleção (seletivida<strong>de</strong>) do atributo A da<br />

relação r.<br />

Dados uma relação r e um atributo A da relação, SC(A,r) é o<br />

número médio <strong>de</strong> registros que satisfazem uma condição <strong>de</strong><br />

igualda<strong>de</strong> no atributo A, dado que pelo menos um registro<br />

satisfaz a condição <strong>de</strong> igualda<strong>de</strong>.<br />

Exemplo:<br />

SC(A,r) = 1 se A é um atributo-chave <strong>de</strong> r;<br />

Para um atributo que não é chave, estimamos que os<br />

valores distintos <strong>de</strong> V(A,r) são distribuídos uniformemente<br />

entre as tuplas, produzindo SC(A,r) = (n r / V(A,r))


Catálogo <strong>de</strong> Informações para Estimativa <strong>de</strong><br />

Custo<br />

As duas últimas estatísticas po<strong>de</strong>m ser<br />

estendidas <strong>de</strong> forma a valer para um conjunto<br />

<strong>de</strong> atributos, ao invés <strong>de</strong> valer para apenas um<br />

atributo.<br />

Se as tuplas da relação r estiverem<br />

armazenadas fisicamente juntas em um arquivo,<br />

a seguinte equação é válida:<br />

B r = [n r , f r ]


Catálogo <strong>de</strong> Informações para Estimativa <strong>de</strong><br />

Custo<br />

<br />

Informações sobre índices:<br />

f i : é o fan-out (número <strong>de</strong> ponteiros) médio dos nós<br />

internos do índice i para índices estruturados em<br />

árvore, como árvores B + ;<br />

HT i : é o número <strong>de</strong> níveis no índice i, ou seja, a altura<br />

do índice i.<br />

LB i : é o número <strong>de</strong> blocos <strong>de</strong> índice <strong>de</strong> nível mais<br />

baixo no índice i, ou seja, o número <strong>de</strong> blocos no<br />

nível <strong>de</strong> folha do índice (o número <strong>de</strong> blocos que<br />

contém os registros folha <strong>de</strong> um índice).


Catálogo <strong>de</strong> Informações para Estimativa <strong>de</strong><br />

Custo<br />

<br />

As variáveis estatísticas são usadas para estimar o tamanho<br />

do resultado e o custo para várias operações e algoritmos.<br />

A estimativa <strong>de</strong> custo do algoritmo A é E A .<br />

<br />

<br />

Para manter as estatísticas precisas, toda vez que uma<br />

relação for modificada tem-se que atualizar as estatísticas.<br />

Contudo, a maioria do sistema não atualiza as estatísticas em<br />

todas as modificações. Atualiza-as periodicamente.<br />

Quanto mais informações forem utilizadas para estimar o<br />

custo da consulta e quanto mais precisas forem essas<br />

informações, melhores serão as estimativas <strong>de</strong> custo.


Medidas do Custo <strong>de</strong> uma Consulta<br />

<br />

O custo <strong>de</strong> uma consulta po<strong>de</strong> ser estimado <strong>de</strong> diversas formas:<br />

Por acessos a disco;<br />

Por tempo <strong>de</strong> uso da CPU;<br />

Pelo tempo <strong>de</strong> comunicação nos BD paralelos<br />

e/ou distribuídos;<br />

<br />

O tempo <strong>de</strong> execução <strong>de</strong> um plano po<strong>de</strong>ria ser usado para<br />

estimar o custo da consulta, contudo em gran<strong>de</strong>s sistemas <strong>de</strong><br />

BD, utiliza-se o número <strong>de</strong> acessos a disco, porque estes<br />

estabelecem o tempo crítico <strong>de</strong> execução do plano (já que são<br />

lentos quando comparados às operações realizadas em<br />

memória).


Medidas do Custo <strong>de</strong> uma Consulta<br />

<br />

Para simplificar nossos cálculos assumiremos que todas as<br />

transferências <strong>de</strong> blocos (do disco para memória) têm o<br />

mesmo custo. Desconsi<strong>de</strong>raremos o tempo <strong>de</strong> latência e o<br />

tempo <strong>de</strong> busca. Também <strong>de</strong>sconsi<strong>de</strong>ramos o custo <strong>de</strong><br />

escrever o resultado final <strong>de</strong> uma operação <strong>de</strong> volta para o<br />

disco.<br />

<br />

Os custos dos algoritmos <strong>de</strong>pen<strong>de</strong>m significativamente do<br />

tamanho do buffer na memória principal. No melhor caso,<br />

todos os dados po<strong>de</strong>m ser lidos para o buffer e o disco não<br />

precisa ser acessado novamente. No pior caso, supomos<br />

que o buffer po<strong>de</strong> manter apenas alguns blocos <strong>de</strong> dados<br />

– aproximadamente um bloco por relação. Geralmente<br />

faremos a suposição do pior caso.


Operação <strong>de</strong> Seleção<br />

<br />

É a varredura <strong>de</strong> arquivos: o operador <strong>de</strong> mais baixo<br />

nível para se ter acesso aos dados.<br />

<br />

São algoritmos <strong>de</strong> procura que localizam e recuperam<br />

os registros que estão <strong>de</strong> acordo com uma condição <strong>de</strong><br />

seleção.<br />

<br />

Tem-se vários algoritmos diferentes, que variam <strong>de</strong><br />

acordo com a complexida<strong>de</strong> da seleção e o uso ou não<br />

<strong>de</strong> índices.


Operação <strong>de</strong> Seleção<br />

<br />

Exemplo <strong>de</strong> algoritmos usados na implementação do<br />

operador select:<br />

Busca Linear (ou força bruta);<br />

Busca Binária;<br />

Utilização <strong>de</strong> índice primário (atributo chave);<br />

Utilização <strong>de</strong> índice primário para recuperar múltiplos<br />

registros (atributo chave);<br />

Utilização <strong>de</strong> um índice cluster para recuperar<br />

múltiplos registros (atributo não chave);<br />

Utilização <strong>de</strong> um índice secundário (Árvore B+) em<br />

uma comparação <strong>de</strong> igualda<strong>de</strong>;<br />

Busca para seleções complexas


Operação <strong>de</strong> Seleção<br />

<br />

Busca para seleções complexas:<br />

Se uma condição <strong>de</strong> uma instrução select é uma<br />

condição conjuntiva – ou seja, é formada por diversas<br />

condições simples conectadas pelo conectivo lógico<br />

AND, o SGBD po<strong>de</strong> usar os seguintes métodos:<br />

Seleção conjuntiva utilizando um índice individual;<br />

Seleção conjuntiva utilizando um índice composto;<br />

Seleção conjuntiva por meio da interseção <strong>de</strong> registros.


Operação <strong>de</strong> Seleção<br />

<br />

Busca para seleções complexas:<br />

Se uma condição <strong>de</strong> uma instrução select é uma<br />

condição disjuntiva – ou seja, é formada por diversas<br />

condições simples conectadas pelo conectivo lógico<br />

OR, a otimização é mais simples.<br />

Pouca otimização po<strong>de</strong> ser feita, pois os registros<br />

que satisfazem a condição disjuntiva são a união dos<br />

registros que satisfazem as condições individuais.


Operação <strong>de</strong> Seleção<br />

Veremos dois <strong>de</strong>les (os básicos):<br />

Aquele que envolve uma Busca Linear;<br />

Aquele que envolve uma Busca Binária.<br />

Consi<strong>de</strong>re uma operação <strong>de</strong> seleção em uma<br />

relação cujas tuplas são armazenadas juntas<br />

em um único arquivo.


Seleção por Busca Linear – A1<br />

<br />

Em uma busca linear, cada bloco <strong>de</strong> arquivo é varrido e<br />

todos os registros são testados para verificar se<br />

satisfazem a condição <strong>de</strong> seleção.<br />

Como todos os blocos precisam ser lidos, E A1 = b r .<br />

<br />

No caso da seleção ser aplicada em um atributo-chave,<br />

po<strong>de</strong>mos supor que a meta<strong>de</strong> dos blocos é varrida antes<br />

<strong>de</strong> o registro ser encontrado, ponto no qual a varredura<br />

termina. A estimativa então será E A1 = (b r /2).


Seleção por Busca Binária – A2<br />

<br />

Se o arquivo é or<strong>de</strong>nado em um atributo e a condição <strong>de</strong> seleção é<br />

uma comparação <strong>de</strong> igualda<strong>de</strong> neste atributo, po<strong>de</strong>mos usar uma<br />

busca binária para localizar os registros que satisfazem a seleção.<br />

Neste caso, a estimativa é:<br />

E A2 = [log 2 (b r )] + [SC(A,r)/f r ] -1<br />

O primeiro termo [log 2 (b r )] contabiliza o custo para localizar a<br />

primeira tupla por meio da busca binária nos blocos;<br />

O número total <strong>de</strong> registros que satisfarão a seleção é SC(A,r), e<br />

esses registros ocuparão [SC(A,r)/f r ] blocos, dos quais um já<br />

havia sido recuperado (por isso o -1).<br />

Se a condição <strong>de</strong> igualda<strong>de</strong> estiver em um atributo-chave, então<br />

SC(A,r) = 1, e a estimativa se reduz a E A2 = [log(b r )].


Cálculo do Custo da Busca Binária<br />

<br />

Acesso aos blocos:<br />

Primeiro acesso (ao bloco central) não encontro o registro<br />

procurado;<br />

Segundo acesso (ao bloco central do lado esquerdo ou direito)<br />

....<br />

Até o pior caso (nono acesso), o registro é encontrando na<br />

última divisão disponível (ou não é encontrado).<br />

<br />

Para 500 blocos:<br />

500 250 125 62,5 31,25 15,62 7,8 3,9 <br />

1,9 (nove divisões)<br />

<br />

Cálculo: log 2 (500) = 9 2 9 = 516 (=~ 500)


Exemplo <strong>de</strong> Seleção por Busca Binária<br />

<br />

Suponha as seguintes informações estatísticas para uma relação<br />

conta:<br />

f conta = 20 (ou seja, 20 tuplas <strong>de</strong> conta cabem em um único<br />

bloco);<br />

V(nome_agência, conta) = 50 (ou seja, existem 50 agências<br />

com nomes diferentes);<br />

V(saldo, conta) = 500 (ou seja, existe 500 valores diferentes <strong>de</strong><br />

saldos nesta relação);<br />

n conta = 10.000 (ou seja, a relação conta possui 10.000 tuplas).<br />

<br />

Consi<strong>de</strong>re a consulta:<br />

σ nome_agência = Perryridge (conta)


Exemplo <strong>de</strong> Seleção por Busca Binária<br />

<br />

<br />

<br />

Como a relação tem 10.000 tuplas, e cada bloco mantém 20 tuplas, o<br />

número <strong>de</strong> blocos é b conta = 500 (10.000/20);<br />

Uma varredura <strong>de</strong> arquivo simples faria 500 acessos a blocos, supondo<br />

que o atributo da condição não fosse atributo-chave. Senão, seriam em<br />

média 250 acessos;<br />

Suponha que conta esteja or<strong>de</strong>nado por nome_agência.<br />

Como V(nome_agência, conta) = 50, esperamos que 10.000/50=200<br />

tuplas da relação conta pertençam à agência Perryridge;<br />

<br />

Essas tuplas caberiam em 200/20 = 10 blocos;<br />

Uma busca binária para encontra o primeiro registro [log 2 (500)] = 9;<br />

<br />

Assim o custo total seria: 9 + 10 – 1 = 18 acessos a bloco.


Operação <strong>de</strong> Seleção<br />

<br />

<br />

<br />

<br />

A otimização <strong>de</strong> consulta para uma operação SELECT é<br />

necessária principalmente em condições <strong>de</strong> seleção<br />

conjuntiva, sempre que mais <strong>de</strong> um dos atributos<br />

envolvidos nas condições possuírem um caminho <strong>de</strong><br />

acesso.<br />

O otimizador <strong>de</strong>ve escolher o caminho <strong>de</strong> acesso que<br />

recupera o menor número <strong>de</strong> registros (gera blocos <strong>de</strong><br />

respostas menores), <strong>de</strong> maneira mais eficiente.<br />

As seleções que separam o menor número <strong>de</strong> tuplas<br />

<strong>de</strong>vem ser realizadas primeiro.<br />

Na escolha entre múltiplas opções o otimizador<br />

consi<strong>de</strong>ra também a seletivida<strong>de</strong> <strong>de</strong> cada condição.


Classificação<br />

<br />

A or<strong>de</strong>nação é bastante importante, uma vez que o<br />

algoritmo é utilizado:<br />

Na implementação do or<strong>de</strong>r by.<br />

Como um componente-chave nos algoritmos <strong>de</strong> sortmerge<br />

usado no join, union e intersection e em<br />

algoritmos <strong>de</strong> eliminação <strong>de</strong> duplicatas para a<br />

operação project.<br />

<br />

A or<strong>de</strong>nação po<strong>de</strong> ser evitada se um índice apropriado<br />

existir <strong>de</strong> forma a permitir o acesso or<strong>de</strong>nado aos<br />

registros.


Classificação<br />

Formas <strong>de</strong> or<strong>de</strong>nação:<br />

Lógica: construção <strong>de</strong> um índice na chave <strong>de</strong><br />

classificação, o qual será usado para ler a<br />

relação na or<strong>de</strong>m <strong>de</strong> classificação.<br />

A leitura <strong>de</strong> tuplas na or<strong>de</strong>m <strong>de</strong> classificação po<strong>de</strong><br />

conduzir a um acesso <strong>de</strong> disco para cada tupla.<br />

Física: as tuplas são gravadas <strong>de</strong> forma<br />

or<strong>de</strong>nada no disco.


Classificação<br />

<br />

O problema <strong>de</strong> classificação po<strong>de</strong> ser tratado sob duas<br />

condições:<br />

Quando a relação cabe completamente na memória<br />

principal:<br />

Técnicas padrões <strong>de</strong> classificação (quicksort entre outras)<br />

po<strong>de</strong>m ser usadas.<br />

Quando a relação é maior que a memória principal <br />

classificação externa:<br />

Algoritmo comum: sort-merge externo<br />

<br />

Para entendê-lo, consi<strong>de</strong>re M o número <strong>de</strong> frames <strong>de</strong> páginas<br />

no buffer da memória principal ( o número <strong>de</strong> blocos <strong>de</strong> disco<br />

cujos conteúdos po<strong>de</strong>m ser colocados no buffer da memória<br />

principal).


Or<strong>de</strong>nação Externa<br />

<br />

A or<strong>de</strong>nação externa é a<strong>de</strong>quada para manipular<br />

arquivos <strong>de</strong> registros gran<strong>de</strong>s, que são armazenados<br />

em disco e que não cabem inteiramente na memória<br />

principal.<br />

A or<strong>de</strong>nação nesse algoritmo é feita por partes –<br />

estratégia merge-sort.<br />

<br />

Fases:<br />

Fase <strong>de</strong> or<strong>de</strong>nação;<br />

Fase <strong>de</strong> fusão.


Inicialização:<br />

i 1;<br />

j b; (tamanho do arquivo em blocos)<br />

k n 0 ; (tamanho do buffer em blocos)<br />

m ⎡ (j/k) ⎤ (maior inteiro)<br />

Fase <strong>de</strong> or<strong>de</strong>nação<br />

Se no buffer cabem 3 blocos,<br />

e o arquivo possui 11 blocos,<br />

será preciso 4 iterações da<br />

fase <strong>de</strong> or<strong>de</strong>nação. As 3<br />

primeiras or<strong>de</strong>narão 9 blocos<br />

e a última or<strong>de</strong>nará 2 blocos.<br />

Enquanto (i


Fase <strong>de</strong> fusão: fundir os subarquivos até que reste apenas 1<br />

Inicialização<br />

Temos 4 subarquivos or<strong>de</strong>nados (m = 4 e k = 3).<br />

i 1;<br />

p ⎡ log k-1 m ⎤; (p é o número <strong>de</strong> passagens da fase <strong>de</strong> fusão)<br />

j m;<br />

p = 2<br />

enquanto (i


Exemplo no Navathe<br />

Se o número <strong>de</strong> blocos do arquivo = 1024<br />

Se o tamanho do buffer = 5 blocos<br />

Na fase <strong>de</strong> or<strong>de</strong>nação serão criados 205 subarquivos<br />

204 com 5 blocos e 1 com 4 blocos<br />

<br />

Na fase <strong>de</strong> fusão, em cada uma das 4 passagens, serão gravados,<br />

respectivamente:<br />

52 subarquivos<br />

13 subarquivos<br />

04 arquivos<br />

01 arquivo<br />

Número <strong>de</strong> subarquivos / tamanho do buffer -1 bloco<br />

Por que -1?<br />

Porque um bloco <strong>de</strong> buffer fica reservado<br />

para armazenar um bloco resultado da fusão.


Sort-merge Externo (Korth)<br />

1. Várias classificações temporárias são executadas:<br />

i = 0;<br />

repeat<br />

leia M blocos da relação, ou o resto da relação,<br />

aquilo que for menor;<br />

or<strong>de</strong>ne a parte da relação que está na memória;<br />

escreva os dados or<strong>de</strong>nados no arquivo temporário<br />

Ri;<br />

i = i + 1;<br />

until o fim da relação


Sort-merge Externo<br />

2. Faz-se o merge nos arquivos temporários. Suponha, por enquanto, que<br />

o número total <strong>de</strong> temporários, N, seja menor do que M, <strong>de</strong> forma que se<br />

consiga alocar um frame <strong>de</strong> página para um bloco <strong>de</strong> cada arquivo<br />

temporário e há espaço para manter uma página <strong>de</strong> resultado.<br />

leia um bloco <strong>de</strong> cada um dos N arquivos Ri, para uma página <strong>de</strong> buffer<br />

na memória;<br />

repeat<br />

escolha a primeira tupla (na or<strong>de</strong>m <strong>de</strong> classificação) entre todas as<br />

páginas do buffer;<br />

escreva a tupla no resultado e apague-a da página <strong>de</strong> buffer;<br />

if a página <strong>de</strong> buffer <strong>de</strong> qualquer temporário Ri está vazia and not fim<br />

<strong>de</strong> arquivo (Ri) then leia o próximo bloco <strong>de</strong> Ri na página <strong>de</strong> buffer;<br />

until todas as páginas <strong>de</strong> buffer estarem vazias;


Consi<strong>de</strong>rações<br />

<br />

<br />

<br />

<br />

<br />

Geralmente, se a relação é muito maior que a memória, po<strong>de</strong> haver<br />

M ou mais temporários gerados na primeira fase, e não será<br />

possível alocar um frame <strong>de</strong> página para cada temporário durante a<br />

fase <strong>de</strong> merge.<br />

Neste caso, faz-se a operação <strong>de</strong> merge em múltiplos passos.<br />

Como há memória suficiente para M-1 páginas <strong>de</strong> buffer <strong>de</strong> entrada,<br />

cada merge terá M-1 temporários como entrada.<br />

Funcionamento próximo sli<strong>de</strong>.<br />

Exemplo: Suponha agora que apenas um tupla caiba em um bloco<br />

(f = 1), e suponha que a memória mantém três frames <strong>de</strong> página no<br />

máximo. Durante os estágios <strong>de</strong> merge, dois frames <strong>de</strong> página são<br />

usados para entrada e um para o resultado.


Funcionamento<br />

<br />

<br />

<br />

<br />

<br />

<br />

Faz-se o merge sobre os primeiros M-1 temporários (conforme <strong>de</strong>scrito<br />

anteriormente) para obter um único temporário para o próximo passo;<br />

Faz-se o merge dos próximos M-1 temporários <strong>de</strong> forma semelhante, e<br />

assim por diante, até que todos os temporários iniciais tenham sido<br />

processados;<br />

Nesse ponto, o número <strong>de</strong> temporários foi reduzido a um fator <strong>de</strong> M–1;<br />

Se esse número reduzido <strong>de</strong> temporários ainda é maior ou igual a M, outro<br />

passo é dado, usando os temporários criados pelo passo anterior;<br />

Esses passos são repetidos tantas vezes quantas forem necessárias, até<br />

que o número <strong>de</strong> temporários seja menor que M;<br />

Então, um passo final gera o resultado classificado.


Exemplo<br />

g<br />

a<br />

d<br />

c<br />

b<br />

e<br />

r<br />

d<br />

m<br />

p<br />

d<br />

24<br />

19<br />

31<br />

33<br />

14<br />

16<br />

16<br />

21<br />

3<br />

2<br />

7<br />

a 14<br />

Relação<br />

inicial<br />

Criar<br />

temporários<br />

a 19<br />

d 31<br />

g 24<br />

b 14<br />

c 33<br />

e 16<br />

d 21<br />

m 3<br />

r 16<br />

a 14<br />

d 7<br />

p 2<br />

Temporários<br />

Passo 1:<br />

<strong>de</strong> merge<br />

a 19<br />

b 14<br />

c 33<br />

d 31<br />

e 16<br />

g 24<br />

a 14<br />

d 7<br />

d 21<br />

m 3<br />

p 2<br />

r 16<br />

Temporários<br />

Passo 2:<br />

<strong>de</strong> merge<br />

a 14<br />

a 19<br />

b 14<br />

c 33<br />

d 7<br />

d 21<br />

d 31<br />

e 16<br />

g 24<br />

m 3<br />

p 2<br />

r 16<br />

Resultado<br />

classificado


Número <strong>de</strong> Acessos a Disco<br />

<br />

Fase <strong>de</strong> or<strong>de</strong>nação:<br />

2 * b, on<strong>de</strong> b é o número <strong>de</strong> blocos do arquivo que está sendo<br />

or<strong>de</strong>nado<br />

Cada bloco b será acessado duas vezes, uma vez para leitura e<br />

outra vez para escrita<br />

<br />

Fase <strong>de</strong> fusão:<br />

2 * (b * log Dm nr), on<strong>de</strong> Dm é o número <strong>de</strong> subarquivos fundidos<br />

em cada fusão e nr é número <strong>de</strong> subarquivos.<br />

O 2 se dá por conta da leitura e escrita <strong>de</strong> cada bloco<br />

O termo interno ao parênteses conta quantas vezes cada bloco<br />

será analisado (lido e escrito)


Operação <strong>de</strong> Junção<br />

<br />

equi_join: <strong>de</strong>signação para uma junção da forma r |X| r.A=s.B<br />

s, em que A e B<br />

são atributos ou conjuntos <strong>de</strong> atributos das relações r e s, respectivamente.<br />

<br />

O exemplo usado será:<br />

<strong>de</strong>positante |X| cliente<br />

<br />

Suponha as seguintes informações <strong>de</strong> catálogo:<br />

n cliente<br />

= 10.000<br />

f cliente<br />

= 25, o que implica b cliente<br />

= 10.000/25 = 400<br />

n <strong>de</strong>positante<br />

= 5.000<br />

f <strong>de</strong>positante<br />

= 50, o que implica b <strong>de</strong>positante<br />

= 5.000/50 = 100<br />

V(nome_cliente, <strong>de</strong>positante) = 2.500, o que implica que, em média,<br />

cada cliente tem duas contas<br />

<br />

Suponha ainda que nome-cliente em <strong>de</strong>positante seja uma chave<br />

estrangeira vinda <strong>de</strong> cliente


Estimativa do Tamanho das Junções<br />

<br />

<br />

<br />

<br />

O produto cartesiano r X s contém n r * n s tuplas.<br />

Cada tupla <strong>de</strong>ste produto cartesiano ocupa s r + s s bytes.<br />

Assim po<strong>de</strong>mos calcular o tamanho do produto<br />

cartesiano.<br />

Para junção natural ... Sejam r(R) e s(S) duas relações:<br />

Se R ∩ S = ∅, então r |X| s é igual a r X s;<br />

Se R ∩ S é uma chave para R, então sabemos que<br />

uma tupla <strong>de</strong> s irá juntar-se com no máximo uma<br />

tupla <strong>de</strong> r. Assim, o número <strong>de</strong> tuplas na junção não<br />

é maior que o número <strong>de</strong> tuplas <strong>de</strong> s.<br />

Se R ∩ S é uma chave estrangeira para S – vinda <strong>de</strong><br />

R – , então o número <strong>de</strong> tuplas em r |X| s é<br />

exatamente igual ao número <strong>de</strong> tuplas em s.


Estimativa do Tamanho das Junções<br />

No exemplo: <strong>de</strong>positante |x| cliente,<br />

nome_cliente em <strong>de</strong>positante é uma chave<br />

estrangeira vinda <strong>de</strong> cliente.<br />

O tamanho do resultado é exatamente<br />

n <strong>de</strong>positante , que é 5.000;<br />

Com calcular o tamanho da junção quando R ∩<br />

S não é uma chave para R ou para S?


Estimativa do Tamanho das Junções<br />

<br />

<br />

<br />

Suponha que cada valor aparece com probabilida<strong>de</strong> igual.<br />

Consi<strong>de</strong>re uma tupla t <strong>de</strong> r e suponha R ∩ S = {A}.<br />

Estima-se que a tupla t produz<br />

n s / V(A,s)<br />

tuplas em r |X| s, uma vez que esse é o número médio <strong>de</strong> tuplas em s<br />

com um <strong>de</strong>terminado valor para os atributos A.<br />

<br />

Consi<strong>de</strong>rando todas as tuplas em r, estima-se que há<br />

n r * n s / V(A, s)<br />

tuplas em r |X| s.


Estimativa do Tamanho das Junções<br />

<br />

Observe que se invertermos os papéis <strong>de</strong> r e s, as estimativas<br />

resultariam em valores diferentes se V(A,r) ≠ V(A,s).<br />

<br />

Se isso acontece, há a probabilida<strong>de</strong> <strong>de</strong> haver tuplas pen<strong>de</strong>ntes<br />

que não participam da junção . A estimativa mais baixa será,<br />

provavelmente, a mais precisa.<br />

<br />

Técnicas mais sofisticadas para a estimativa do tamanho da junção<br />

<strong>de</strong>vem ser usadas se a hipótese <strong>de</strong> distribuição uniforme não pu<strong>de</strong>r<br />

ser consi<strong>de</strong>rada.


Estimativa do Tamanho das Junções<br />

<br />

Calculando a estimativa do tamanho para <strong>de</strong>positante<br />

|X| clientes, sem utilizar informações sobre chaves<br />

entrangeiras.<br />

<br />

Como V(nome_cliente, <strong>de</strong>positante) = 2.500 e<br />

V(nome_cliente, cliente) = 10.000, as duas estimativas<br />

que obtemos são:<br />

(10.000 * 5.000) / 2.500 = 20.000<br />

(5.000 * 10.000)/10.000 = 5.000


Junção <strong>de</strong> Laço Aninhado<br />

for each tupla t r in r do<br />

begin<br />

for each tupla ts in s do<br />

begin<br />

teste o par (tr, ts) para ver se<br />

satisfazem a condição <strong>de</strong> junção;<br />

se satisfizerem, adicione tr.ts ao<br />

resultado<br />

end<br />

end<br />

r: relação externa<br />

s: relação interna<br />

t r .t s : tupla obtida concatenando os valores dos atributos das tuplas t r e<br />

t s


Junção <strong>de</strong> Laço Aninhado<br />

<br />

<br />

<br />

<br />

<br />

Este algoritmo não requer índices e po<strong>de</strong> ser usado seja qual for a<br />

condição <strong>de</strong> junção.<br />

É um algoritmo caro já que examina todos os pares <strong>de</strong> tuplas nas duas<br />

relações. O número <strong>de</strong> pares <strong>de</strong> tuplas a ser consi<strong>de</strong>rado é n r<br />

* n s<br />

(para<br />

cada registro r tem-se que executar uma varredura completa em s).<br />

No pior caso o buffer po<strong>de</strong> manter apenas um bloco <strong>de</strong> cada relação, e um<br />

total <strong>de</strong> nr * bs + br acessos à blocos serão necessários (ou seja, os blocos<br />

da relação r (br) são lidos uma vez por ocasião do laço mais externo e, os<br />

blocos da relação s (bs) são lidos para cada vez que uma tupla <strong>de</strong> r precisa<br />

ser comparada com todas as tuplas <strong>de</strong> s por ocasião do laço mais interno)<br />

No melhor caso, há espaço suficiente para que ambas as relações caibam<br />

na memória, assim cada bloco terá <strong>de</strong> ser lido somente uma vez,<br />

conseqüentemente, apenas br + bs acessos à blocos serão necessários.<br />

Note que, se a relação menor couber completamente na memória, é melhor<br />

usar essa relação como a mais interna.


Exemplo<br />

<br />

<br />

<br />

<br />

<br />

Consi<strong>de</strong>re a junção natural <strong>de</strong> <strong>de</strong>positante e cliente.<br />

Suponha que não existem índices para estas relações.<br />

Suponha que <strong>de</strong>positante é a relação mais externa e<br />

cliente é a relação mais interna.<br />

5.000 * 10.000 tuplas serão examinadas.<br />

Pior caso: 5.000 * 400 + 100 = 2.000.100 acessos à<br />

disco.<br />

Melhor caso: 400 + 100 = 500 acessos à disco.<br />

Trocando as relações dos laços internos e externos:<br />

10.000 * 100 + 400: 1.000.400 acessos à disco.


Merge-junção (Korth)<br />

Sejam r(R) e s(S) relações cuja junção natural<br />

será calculada, e seja R ∩ S a notação para<br />

seus atributos em comum.<br />

Suponha que ambas as relações estejam<br />

classificadas nos atributos R ∩ S.<br />

A junção <strong>de</strong>stas relações po<strong>de</strong> ser feita por<br />

meio <strong>de</strong> um merge.


pr := en<strong>de</strong>reço da primeira tupla <strong>de</strong> r;<br />

ps := en<strong>de</strong>reço da primeira tupla <strong>de</strong> s;<br />

while (ps nulo and pr nulo) do<br />

begin<br />

ts := tupla para qual ps aponta;<br />

Ss := {ts};<br />

configure ps para apontar para a próxima tupla <strong>de</strong> s;<br />

acabou := false;<br />

while (not acabou and ps nulo) do<br />

begin<br />

ts’ := tupla para qual ps aponta;<br />

if (ts’[AtribJunção] = ts[AtribJunção])<br />

then begin<br />

Ss = Ss ∪ {ts’};<br />

configure ps para apontar para<br />

a próxima tupla <strong>de</strong> s;<br />

end<br />

else acabou := verda<strong>de</strong>iro;<br />

end;<br />

// permanece varrendo s enquanto as tuplas contiverem valores iguais para o<br />

atributo <strong>de</strong> junção, e as coloca em uma relação auxiliar.


tr := tupla para a qual pr aponta;<br />

while ( pr nulo and tr[AtribJunção] < ts[AtribJunção]) do<br />

begin<br />

configure pr para apontar para a próxima tupla<br />

<strong>de</strong> r;<br />

tr := tupla para qual pr aponta;<br />

end<br />

// percorre r enquanto não encontrar uma tupla com um valor no atributo <strong>de</strong><br />

junção igual ou maior ao valor no atributo <strong>de</strong> junção das tuplas <strong>de</strong> s que estão<br />

na relação auxiliar<br />

while (pr nulo and tr[AtribJunção] = ts[AtribJunção]) do<br />

begin<br />

for each rs in Ss do<br />

begin<br />

adicione ts.tr ao resultado;<br />

end<br />

configure pr para apontar para a próxima tupla<br />

<strong>de</strong> r;<br />

tr := tupla para a qual pr aponta;<br />

end;<br />

// encontrando a tupla <strong>de</strong> r que <strong>de</strong>ve ser juntar às tuplas <strong>de</strong> Ss, realiza a<br />

concatenação das tuplas, percorrendo r para ver se existem outras a serem<br />

concatenadas.<br />

End;


Merge-junção<br />

<br />

Suponha <strong>de</strong>positante |x| cliente. Com o atributo <strong>de</strong><br />

junção sendo o nome do cliente. As relações já estão<br />

or<strong>de</strong>nadas neste atributo.<br />

<br />

O custo da junção é 400 + 100 = 500 acessos à disco.<br />

<br />

Caso a exigência <strong>de</strong> S caber em memória principal não<br />

pu<strong>de</strong>r ser atendida, um algoritmo <strong>de</strong> junção à parte <strong>de</strong>ve<br />

ser executado para junção tr à Ss.<br />

<br />

Caso as relações não estejam or<strong>de</strong>nadas mas possuam<br />

índices, o merge-junção po<strong>de</strong> ser executado usando os<br />

índices.


Junção Sort-merge (Navathe)<br />

<br />

<br />

<br />

<br />

<br />

Se os registros <strong>de</strong> R e S estiverem classificados (or<strong>de</strong>nados)<br />

fisicamente pelos atributos <strong>de</strong> junção A e B, respectivamente,<br />

po<strong>de</strong>remos implementar a junção da maneira mais eficiente<br />

possível.<br />

Ambos os arquivos são varridos simultaneamente na or<strong>de</strong>m dos<br />

atributos <strong>de</strong> junção, fazendo a correspondência dos registros que<br />

possuem os mesmos valores para A e B.<br />

Se os arquivos não estiverem classificados, eles <strong>de</strong>verão ser<br />

classificados primeiro por meio <strong>de</strong> uma or<strong>de</strong>nação externa.<br />

Pares <strong>de</strong> blocos <strong>de</strong> arquivos são or<strong>de</strong>nadamente copiados para<br />

buffers <strong>de</strong> memória, e os registros <strong>de</strong> cada arquivos são varridos<br />

apenas uma vez (a menos que A e B não sejam atributos chaves e,<br />

nesse caso, o método precisa ser modificado).<br />

Índices proporcionam a capacida<strong>de</strong> <strong>de</strong> acessar (varrer) os registros<br />

na or<strong>de</strong>m dos atributos <strong>de</strong> junção, mas os registros <strong>de</strong> fato estão<br />

fisicamente espalhados pelos blocos do arquivo.


Junção Sort-merge<br />

A seguir, um esboço do algoritmo para Junção,<br />

Projeção, União, Interseção e Diferença por<br />

meio <strong>de</strong> sort-merge, quando R possui n tuplas e<br />

S possui m tuplas.


T R |X| A=B S<br />

Or<strong>de</strong>nar as n tuplas <strong>de</strong> R baseando-se no atributo A;<br />

Or<strong>de</strong>nar as m tuplas <strong>de</strong> S baseando-se no atributo B;<br />

Inicializar i 1 , j 1;<br />

Enquanto (i


{<br />

(* Ri[A] = Sj[B], portanto realizamos o output <strong>de</strong> uma tupla: resultado<br />

da junção*)<br />

output a tupla combinada em T;<br />

(* output outras tuplas correspon<strong>de</strong>ntes a Ri se houver*)<br />

l j + 1;<br />

enquanto (l


T π (R)<br />

Criar uma tupla t[] em T’ para cada tupla t <strong>de</strong> R;<br />

(*T’ contém o resultado da projeção ANTES da eliminação <strong>de</strong> duplicatas*)<br />

Se incluir uma chave <strong>de</strong> R<br />

então T T’;<br />

Senão<br />

{<br />

or<strong>de</strong>nar as tuplas <strong>de</strong> T’<br />

inicializar i 1, j 2;<br />

enquanto i


T R ∪ S<br />

Or<strong>de</strong>nar as tuplas <strong>de</strong> R e S utilizando os mesmos e únicos atributos <strong>de</strong> or<strong>de</strong>nação;<br />

Inicializar i 1; j 1;<br />

Enquanto (i


T R ∩ S<br />

Or<strong>de</strong>nar as tuplas <strong>de</strong> R e S utilizando os mesmos e únicos atributos <strong>de</strong> or<strong>de</strong>nação;<br />

Inicializar i 1; j 1;<br />

Enquanto (i


T R - S<br />

Or<strong>de</strong>nar as tuplas <strong>de</strong> R e S utilizando os mesmos e únicos atributos <strong>de</strong> or<strong>de</strong>nação;<br />

Inicializar i 1; j 1;<br />

Enquanto (i


Merge-junção - Consi<strong>de</strong>rações<br />

<br />

<br />

<br />

<br />

Em relação ao algoritmo apresentado por (Korth): O algoritmo exige<br />

que a relação auxiliar caiba na memória principal. Modificações no<br />

algoritmo <strong>de</strong>vem ser feitas caso essa exigência não possa ser<br />

atendida.<br />

Dado que as relações estão na or<strong>de</strong>m <strong>de</strong> classificação, as tuplas<br />

com o mesmo valor nos atributos <strong>de</strong> junção estão em or<strong>de</strong>m<br />

consecutiva. Assim, cada tupla na or<strong>de</strong>m <strong>de</strong> classificação precisa<br />

ser lida somente uma vez, e, como resultado, cada bloco também é<br />

lido somente uma vez.<br />

Em relação ao algoritmo do Navathe, tem-se que assumir que<br />

conjuntos <strong>de</strong> tuplas com o mesmo valor no atributo <strong>de</strong> junção<br />

precisam estar carregadas na memória ao mesmo tempo;<br />

Então, para ambos, o número <strong>de</strong> acessos à disco é igual à soma do<br />

número <strong>de</strong> blocos em ambos as relações, br + bs.


Implementação do Outer Join<br />

A junção externa po<strong>de</strong> ser obtida por meio da<br />

modificação dos algoritmos <strong>de</strong> junção, como a<br />

junção <strong>de</strong> laços aninhados, sort-merge ou <strong>de</strong><br />

junção hash;<br />

Ou, <strong>de</strong> forma alternativa e simplificada, por meio<br />

da execução <strong>de</strong> uma combinação <strong>de</strong><br />

operadores da álgebra relacional.


Implementação do Outer Join<br />

<br />

Por exemplo, consi<strong>de</strong>re a consulta:<br />

select unome, pnome, dnome<br />

from empregado left outer join <strong>de</strong>partamento on<br />

dno=dnumero;<br />

<br />

Essa operação <strong>de</strong> junção externa é equivalente à<br />

seguinte seqüência <strong>de</strong> operaçoes da álgebra relacional:


Implementação do Outer Join<br />

<br />

Calcule a junção interna entre as tabelas.<br />

Temp1 π unome, pnome, dnome (empregado |X| <strong>de</strong>partamento)<br />

<br />

Encontre as tuplas <strong>de</strong> empregado que não aparecem no<br />

resultado da junção.<br />

Temp2 π unome, pnome (empregado) - π unome, pnome (Temp1)


Implementação do Outer Join<br />

<br />

Complete cada tupla da relação Temp2 com valor null<br />

para o campo dnome.<br />

Temp2 Temp2 X ‘NULL’<br />

<br />

Aplique a operação union em Temp1 e Temp2 para<br />

produzir o resultado do left outer join.<br />

Resultado Temp1 υ Temp2<br />

<br />

O custo <strong>de</strong>ssa junção externa é a soma dos custos da<br />

junção interna, das projeções e da união realizadas.


Junções Complexas<br />

Junção com condição conjuntiva:<br />

r |X| θ ∧ θ ∧ ... θ s<br />

As junções nas condições individuais po<strong>de</strong>m ser<br />

resolvidas, por exemplo, pelo algoritmo <strong>de</strong> junção por laços<br />

aninhados:<br />

r |X| θ s, r |X| θ s, r |X| θ s e assim por diante.<br />

1 2 n<br />

1 2 n<br />

A junção global por ser realizada calculando, primeiro o<br />

resultado <strong>de</strong> uma <strong>de</strong>ssas junções mais simples e <strong>de</strong>pois<br />

testando (a esse resultado) as tuplas produzidas pelas<br />

outras junções.


Junções Complexas<br />

Junção com condição disjuntiva:<br />

r |X| θ ∨ θ ∨ ... θ s<br />

1 2 n<br />

Neste caso, a junção po<strong>de</strong> ser calculada como a<br />

união dos registros nas junções individuais.


Junções Complexas<br />

Suponha r 1 r 2 ... r n em que as junções estão expressas<br />

sem or<strong>de</strong>m. Com n = 3, há 12 or<strong>de</strong>ns <strong>de</strong> junção diferentes:<br />

r1 (r2 r3)<br />

r2 (r1 r3)<br />

r3 (r1 r2)<br />

r1 (r3 r2)<br />

r2 (r3 r1)<br />

r3 (r2 r1)<br />

(r2 r3) r1<br />

(r1 r3) r2<br />

(r1 r2) r3<br />

(r3 r2) r1<br />

(r3 r1) r2<br />

(r2 r1) r3


Junções Complexas<br />

Em geral, com n relações, há (2(n-1))! / (n-1)!<br />

Or<strong>de</strong>ns <strong>de</strong> junção diferentes. Exemplos: Com n<br />

= 5 o n° é 1680 e com n = 7, o n° é 665.280.<br />

Felizmente, não é necessário gerar todas as<br />

expressões equivalentes a uma <strong>de</strong>terminada<br />

expressão.<br />

Uma <strong>de</strong>svantagem da otimização baseada no<br />

custo é o custo da própria otimização.


Junções Complexas<br />

Duas árvores <strong>de</strong> consulta (junção) profundas<br />

à esquerda


Junções Complexas<br />

O otimizador escolherá a árvore que possuir o<br />

menor custo estimado.<br />

Com árvores profundas a esquerda, o filho à<br />

direita é consi<strong>de</strong>rado ser a relação interna, para<br />

o caso da execução <strong>de</strong> laços aninhados.<br />

A idéia-chave sob o ponto <strong>de</strong> vista do otimizador<br />

em relação à or<strong>de</strong>m das junções é encontrar<br />

uma or<strong>de</strong>m que irá reduzir o tamanho dos<br />

resultados intermediários.


Junções Complexas<br />

<br />

Consi<strong>de</strong>re uma junção envolvendo três relações:<br />

empréstimo |X| <strong>de</strong>positante |X| cliente<br />

<br />

Neste caso, além da escolha da estratégia para o processamento<br />

da junção, tem-se ainda que escolher qual junção calcular primeiro.<br />

Vejamos algumas estratégias:<br />

Estratégia 1: calcule a junção <strong>de</strong>positante |X| cliente usando<br />

qualquer técnicas. Usando o resultado intermediário, calcule:<br />

empréstimo |X| (<strong>de</strong>positante |X| cliente);<br />

Estratégia 2: faça como na Estratégia 1, mas calcule primeiro<br />

empréstimo |X| <strong>de</strong>positante, e então faça a junção do resultado<br />

com cliente.<br />

Outra or<strong>de</strong>m <strong>de</strong> junções po<strong>de</strong> ser feita.


Junções Complexas<br />

Estratégia 3: Em vez <strong>de</strong> executar duas junções,<br />

execute o par <strong>de</strong> junções, da seguinte forma:<br />

Construa dois índices:<br />

Um para o número_empréstimo em empréstimo;<br />

Um para o nome_cliente em cliente.<br />

Consi<strong>de</strong>re cada tupla t em <strong>de</strong>positante. Para cada t, procure<br />

as tuplas correspon<strong>de</strong>ntes em cliente e as tuplas<br />

correspon<strong>de</strong>ntes em empréstimo.<br />

Assim, cada tupla <strong>de</strong> <strong>de</strong>positante é examinada exatamente<br />

uma vez.<br />

O custo relativo <strong>de</strong>sse procedimento <strong>de</strong>pen<strong>de</strong> da<br />

forma como as relações estão armazenadas, da<br />

distribuição <strong>de</strong> valores <strong>de</strong>ntro das colunas e da<br />

presença <strong>de</strong> índices.


Eliminação <strong>de</strong> Duplicida<strong>de</strong><br />

<br />

<br />

<br />

<br />

<br />

Po<strong>de</strong>-se implementar a eliminação <strong>de</strong> duplicida<strong>de</strong> usando a<br />

classificação.<br />

As tuplas idênticas aparecerão adjacentes umas às outras após a<br />

classificação, e todas, exceto uma cópia, po<strong>de</strong>m ser removidas.<br />

No sort-merge, as duplicatas encontradas enquanto um temporário<br />

está sendo criado po<strong>de</strong>m ser removidas antes que ele seja escrito<br />

no disco, reduzindo, assim, o número <strong>de</strong> transferências <strong>de</strong> blocos.<br />

Assim, po<strong>de</strong>-se dizer que o custo <strong>de</strong> eliminar as duplicatas é o<br />

custo <strong>de</strong> classificar uma relação.<br />

Devido ao custo relativamente alto da eliminação <strong>de</strong> duplicida<strong>de</strong>, as<br />

linguagens <strong>de</strong> consulta comerciais exigem um pedido explícito do<br />

usuário para remover duplicatas; caso contrário, as duplicatas são<br />

mantidas.


Operação <strong>de</strong> Projeção<br />

<br />

Po<strong>de</strong>-se executar a projeção por meio da execução da<br />

projeção em cada tupla, resultando uma relação que<br />

po<strong>de</strong>ria ter registros duplicados, e então, remover os<br />

registros duplicados.<br />

<br />

Se os atributos na lista <strong>de</strong> projeção incluem as chaves<br />

da relação (primária e/ou candidatas), nenhuma<br />

duplicata existirá.<br />

<br />

O tamanho <strong>de</strong> um projeção da forma Π A (r) é calculado<br />

como V(A,r), uma vez que a projeção elimina as<br />

duplicatas.


Transformações <strong>de</strong> Expressões<br />

Relacionais<br />

Uma consulta po<strong>de</strong> ser expressa <strong>de</strong> diversas<br />

maneiras diferentes, com diferentes custos <strong>de</strong><br />

avaliação.<br />

Equivalência <strong>de</strong> Expressões;<br />

Regras <strong>de</strong> Equivalência;<br />

Exemplos <strong>de</strong> Transformações;<br />

Or<strong>de</strong>namento <strong>de</strong> Junções.


<strong>Otimização</strong> Algébrica<br />

Objetivo do passo <strong>de</strong> transformação<br />

Entrada: Árvore da consulta inicial;<br />

Saída: Árvore da consulta otimizada (po<strong>de</strong><br />

manter a mesma árvore).<br />

Base:<br />

Regras <strong>de</strong> equivalência algébrica<br />

Devem ser conhecidas pelo otimizador para que<br />

possam ser geradas transformações válidas.<br />

Algoritmo <strong>de</strong> otimização algébrica<br />

Indica a or<strong>de</strong>m <strong>de</strong> aplicação das regras e <strong>de</strong> outros<br />

processamentos <strong>de</strong> otimização.


Equivalência <strong>de</strong> Expressões<br />

Consi<strong>de</strong>rando as tabelas a seguir e suas<br />

instâncias, encontre os nomes <strong>de</strong> todos os<br />

clientes que possuem uma conta em qualquer<br />

agência localizada no Brooklyn.<br />

π nome_cliente ( σ cida<strong>de</strong>_agência = “Brooklyn” (agência |X| (conta |X|<br />

<strong>de</strong>positante)))<br />

<br />

Para resolver esta expressão, seguindo a forma como<br />

ela está escrita, é necessário criar uma relação<br />

intermediária gran<strong>de</strong> (a junção das três relações, como<br />

posto no sli<strong>de</strong> 86).


710000<br />

Brooklyn<br />

Brighton<br />

370000<br />

Rye<br />

North Town<br />

30000<br />

Bennington<br />

Pownal<br />

8000000<br />

Horseneck<br />

Round Hill<br />

40000<br />

Horseneck<br />

Mianus<br />

170000<br />

Horseneck<br />

Perrydige<br />

210000<br />

Palo Alto<br />

Redwood<br />

900000<br />

Brooklyn<br />

Downtown<br />

fundos<br />

cida<strong>de</strong>_agência<br />

nome_agência<br />

Stamford<br />

Walnut<br />

Green<br />

Brooklyn<br />

Senator<br />

Brooks<br />

Woodsi<strong>de</strong><br />

Sand Hill<br />

Glenn<br />

Palo Alto<br />

Alma<br />

Johnson<br />

Pittsfield<br />

Spring<br />

Adams<br />

Princeton<br />

Nassau<br />

Williams<br />

Stamford<br />

Putnam<br />

Turner<br />

Pittfield<br />

Park<br />

Lindsay<br />

Rye<br />

North<br />

Curry<br />

Harrison<br />

Main<br />

Hayes<br />

Rye<br />

North<br />

Smith<br />

Harrison<br />

Main<br />

Jones<br />

cida<strong>de</strong>_cliente<br />

rua_cliente<br />

nome_cliente<br />

A-222<br />

Lindsay<br />

A-217<br />

Jones<br />

A-201<br />

Johnson<br />

A-305<br />

Turner<br />

A-102<br />

Hayes<br />

A-215<br />

Smith<br />

A-101<br />

Johnson<br />

número_conta<br />

nome_cliente<br />

agência<br />

<strong>de</strong>positante<br />

cliente<br />

750<br />

A-217<br />

Bringhton<br />

700<br />

A-222<br />

Redwood<br />

900<br />

A-201<br />

Bringhton<br />

350<br />

A-305<br />

Round Hill<br />

400<br />

A-102<br />

Perryridge<br />

700<br />

A-215<br />

Mianus<br />

500<br />

A-101<br />

Downtown<br />

saldo<br />

número_conta<br />

nome_agência<br />

conta


Junção (conta |X| <strong>de</strong>positante)<br />

nome_agência<br />

número_conta<br />

saldo<br />

nome_cliente<br />

número_conta<br />

Downtown<br />

A-101<br />

500<br />

Johnson<br />

A-101<br />

Mianus<br />

A-215<br />

700<br />

Smith<br />

A-215<br />

Perryridge<br />

A-102<br />

400<br />

Hayes<br />

A-102<br />

Round Hill<br />

A-305<br />

350<br />

Turner<br />

A-305<br />

Bringhton<br />

A-201<br />

900<br />

Johson<br />

A-201<br />

Redwood<br />

A-222<br />

700<br />

Lindsay<br />

A-222<br />

Bringhton<br />

A-217<br />

750<br />

Jones<br />

A-217<br />

Junção (agência |X| (conta |X| <strong>de</strong>positante))<br />

nome_agência<br />

número_conta<br />

saldo<br />

nome_cliente<br />

nome_agência<br />

cida<strong>de</strong>_agência<br />

fundos<br />

Downtown<br />

Mianus<br />

Perryridge<br />

Round Hill<br />

Bringhton<br />

Redwood<br />

A-101<br />

A-215<br />

A-102<br />

A-305<br />

A-201<br />

A-222<br />

500<br />

700<br />

400<br />

350<br />

900<br />

700<br />

Johnson<br />

Smith<br />

Hayes<br />

Turner<br />

Johson<br />

Lindsay<br />

Downtown<br />

Mianus<br />

Perrydige<br />

Round Hill<br />

Brighton<br />

Redwood<br />

Brooklyn<br />

Horseneck<br />

Horseneck<br />

Horseneck<br />

Brooklyn<br />

Palo Alto<br />

900000<br />

40000<br />

170000<br />

8000000<br />

710000<br />

210000<br />

Bringhton<br />

A-217<br />

750<br />

Jones<br />

Brighton<br />

Brooklyn<br />

710000


Equivalência <strong>de</strong> Expressões<br />

<br />

Entretanto, somente as tuplas que pertencem às<br />

agências localizadas no “Brooklyn” são interessantes.<br />

<br />

Reescrevendo a consulta, consegue-se eliminar a<br />

necessida<strong>de</strong> <strong>de</strong> consi<strong>de</strong>rar as tuplas que não têm<br />

cida<strong>de</strong>_agência = “Brooklyn”, reduzindo o tamanho do<br />

resultado intermediário:<br />

π nome_cliente (( σ cida<strong>de</strong>_agência = “Brooklyn” (agência)) |X| (conta |X|<br />

<strong>de</strong>positante))


Junção (conta |X| <strong>de</strong>positante)<br />

nome_agência<br />

número_conta<br />

saldo<br />

nome_cliente<br />

número_conta<br />

Downtown<br />

A-101<br />

500<br />

Johnson<br />

A-101<br />

Mianus<br />

Perryridge<br />

Round Hill<br />

Bringhton<br />

Redwood<br />

Bringhton<br />

A-215<br />

A-102<br />

A-305<br />

A-201<br />

A-222<br />

A-217<br />

700<br />

400<br />

350<br />

900<br />

700<br />

750<br />

Smith<br />

Hayes<br />

Turner<br />

Johnson<br />

Lindsay<br />

Jones<br />

A-215<br />

A-102<br />

A-305<br />

A-201<br />

A-222<br />

A-217<br />

σ cida<strong>de</strong>_agência = “Brooklyn”<br />

(agência)<br />

nome_agência<br />

Downtown<br />

Brighton<br />

cida<strong>de</strong>_agência<br />

Brooklyn<br />

Brooklyn<br />

fundos<br />

900000<br />

710000<br />

(σ cida<strong>de</strong>_agência = “Brooklyn”<br />

(agência)) |X| (conta |X| <strong>de</strong>positante)<br />

nome_agência<br />

número_conta<br />

saldo<br />

nome_cliente<br />

cida<strong>de</strong>_agência<br />

fundos<br />

Downtown<br />

A-101<br />

500<br />

Johnson<br />

Brooklyn<br />

900000<br />

Bringhton<br />

A-201<br />

900<br />

Johnson<br />

Brooklyn<br />

710000<br />

Bringhton<br />

A-217<br />

750<br />

Jones<br />

Brooklyn<br />

710000


Equivalência <strong>de</strong> Expressões<br />

π nome_cliente<br />

π nome_cliente<br />

σ cida<strong>de</strong>_agência = “Brooklyn”<br />

|X|<br />

|X|<br />

σ cida<strong>de</strong>_agência = “Brooklyn”<br />

|X|<br />

agência<br />

|X|<br />

agência<br />

conta<br />

<strong>de</strong>positante<br />

conta<br />

<strong>de</strong>positante<br />

(a) Árvore da expressão inicial<br />

(b) Árvore da expressão transformada


Equivalência <strong>de</strong> Expressões<br />

<br />

Dada uma expressão <strong>de</strong> álgebra relacional, é função do<br />

otimizador <strong>de</strong> consulta propor um plano <strong>de</strong> avaliação da<br />

consulta que gere o mesmo resultado da expressão<br />

fornecida e que seja uma maneira menos onerosa <strong>de</strong><br />

gerar o resultado (ou que, pelo menos, não seja muito<br />

mais cara que a maneira mais barata).<br />

<br />

Para isso o otimizador precisa gerar planos alternativos<br />

que produzam o mesmo resultado da expressão dada e<br />

escolher o menos caro.


Regras <strong>de</strong> Equivalência Algébrica<br />

<br />

<br />

<br />

<br />

Uma regra <strong>de</strong> equivalência diz que expressões <strong>de</strong> duas formas são<br />

equivalentes se po<strong>de</strong>mos transformar uma na outra preservando a<br />

equivalência.<br />

Preservar a equivalência significa que as relações geradas pelas<br />

duas expressões têm o mesmo conjunto <strong>de</strong> atributos e contêm o<br />

mesmo conjunto <strong>de</strong> tuplas, embora seus atributos possam estar<br />

or<strong>de</strong>nados <strong>de</strong> forma diferente.<br />

As regras <strong>de</strong> equivalência são usadas pelo otimizador para<br />

transformar expressões em outras logicamente equivalentes.<br />

Assuma que:<br />

θ: <strong>de</strong>nota predicados;<br />

L: <strong>de</strong>notas listas <strong>de</strong> atributos;<br />

E: <strong>de</strong>nota expressões da álgebra relacional.


Regras <strong>de</strong> Equivalência Algébrica<br />

1. Operações <strong>de</strong> seleção conjuntivas po<strong>de</strong>m ser quebradas<br />

em uma seqüência <strong>de</strong> seleções individuais (cascata <strong>de</strong> σ).<br />

σ θ1 ∧ θ2 (E) = σ θ1 (σ θ2 (E))<br />

2. Operações <strong>de</strong> seleção são comutativas.<br />

σ θ1 (σ θ2 (E)) = σ θ2 (σ θ1 (E))<br />

3. Apenas as operações finais em uma seqüência <strong>de</strong><br />

operações <strong>de</strong> projeção são necessárias, as outras po<strong>de</strong>m<br />

ser omitidas (cascata <strong>de</strong> π).<br />

π L1 (π L2 (...(π Ln (E))...)) = π L1 (E)


Regras <strong>de</strong> Equivalência Algébrica<br />

4. Seleções po<strong>de</strong>m ser combinadas com produtos<br />

cartesianos e junções teta.<br />

σ θ (E1 X E2) = E1 |X| θ E2<br />

5. Operações <strong>de</strong> junção teta são comutativas.<br />

E1 |X| θ E2 = E2 |X| θ E1<br />

6. Operações <strong>de</strong> junção natural são associativas.<br />

(E1 |X| E2) |X| E3 = E1 |X| (E2 |X| E3)<br />

7. Comutativida<strong>de</strong> <strong>de</strong> π e |X| (ou X): similar à 6.


Regras <strong>de</strong> Equivalência Algébrica<br />

8. Comutativida<strong>de</strong> <strong>de</strong> Operações <strong>de</strong> Conjunto<br />

R ∪ S ≡ S ∪ R<br />

R ∩ S ≡ S ∩ R<br />

e<br />

- A operação “⎯” não é comutativa.<br />

9. Associativida<strong>de</strong> <strong>de</strong> Operações Produtórias e <strong>de</strong> Conjunto<br />

(“οX”)<br />

(R “οX” S) “οX” T ≡ R “οX” (S “οX” T)<br />

- Por “οX” entenda-se: X ou X θ ou ou ∪ ou ∩.<br />

- A operação “⎯” não é associativa.


Regras <strong>de</strong> Equivalência Algébrica<br />

9. Associativida<strong>de</strong> <strong>de</strong> Operações Produtórias e <strong>de</strong> Conjunto<br />

(“οX”)<br />

(R “οX” S) “οX” T ≡ R “οX” (S “οX” T)<br />

Observação: Predicados <strong>de</strong> junção <strong>de</strong>vem ser<br />

<strong>de</strong>vidamente ajustados na associativida<strong>de</strong> <strong>de</strong> operações<br />

produtórias. Exemplo: Seja θ 1 um predicado sobre<br />

atributos <strong>de</strong> R e S, θ 2 um predicado sobre atributos <strong>de</strong> S<br />

e T, e θ 3 um predicado sobre atributos <strong>de</strong> R e T. Então,<br />

(R “X” θ1 S) “X” θ2 ∧ θ3 T ≡ R “X” θ1 ∧ θ3 (S “X” θ2 T)


Regras <strong>de</strong> Equivalência Algébrica<br />

10. Comutativida<strong>de</strong> <strong>de</strong> Seleção e Operações <strong>de</strong> Conjunto<br />

(“ο”)<br />

σ c (R “ο” S) ≡ (σ c (R)) “ο” (σ c (S))<br />

- Por “ο” entenda-se: ∪ ou ∩ ou ⎯<br />

11. Comutativida<strong>de</strong> <strong>de</strong> Projeção e União<br />

π listaAtributos (R ∪ S) ≡ (π listaAtributos (R)) ∪ (π listaAtributos (S))<br />

- As operações “⎯” e “∩” não são comutativas.


Regras <strong>de</strong> Equivalência Algébrica<br />

12. Fusão <strong>de</strong> Seleções e Operações Produtórias<br />

(a) σ c (R X S) ≡ R X θ = σ c S<br />

(b) σ c (R X S) ≡ R S<br />

c<br />

ou<br />

ou<br />

(c) R X θ = σ c S ≡ R S<br />

c


Exemplos <strong>de</strong> Transformações<br />

Exemplo 1:<br />

π nome_cliente ( σ cida<strong>de</strong>_agência = “Brooklyn” (agência |X| (conta |X| <strong>de</strong>positante)))<br />

π nome_cliente (( σ cida<strong>de</strong>_agência = “Brooklyn” (agência)) |X| (conta |X| <strong>de</strong>positante))<br />

Exemplo 2:<br />

π nome_cliente ( σ cida<strong>de</strong>_agência = “Brooklyn” ∧ saldo > 1000 (agência |X| (conta |X| <strong>de</strong>positante)))<br />

π nome_cliente ( σ cida<strong>de</strong>_agência = “Brooklyn” ∧ saldo > 1000 ((agência |X| conta) |X| <strong>de</strong>positante))<br />

π nome_cliente ( σ cida<strong>de</strong>_agência = “Brooklyn” ∧ saldo > 1000 (agência |X| conta)) |X| <strong>de</strong>positante)<br />

Exemplo3: Examinando uma subexpressão interna:<br />

σ cida<strong>de</strong>_agência = “Brooklyn” ∧ saldo > 1000 (agência |X| conta))<br />

σ cida<strong>de</strong>_agência = “Brooklyn” (σ saldo > 1000 (agência |X| conta))<br />

σ cida<strong>de</strong>_agência = “Brooklyn” (agência) |X| σ saldo > 1000 (conta)<br />

Exemplo 4: Usando projeções<br />

π nome_cliente (( σ cida<strong>de</strong>_agência = “Brooklyn” (agência) |X| conta) |X| <strong>de</strong>positante)<br />

π nome_cliente ((π número_conta (( σ cida<strong>de</strong>_agência = “Brooklyn” (agência)) |X| conta)) |X| <strong>de</strong>positante)


Or<strong>de</strong>nando Junções<br />

<br />

Uma boa or<strong>de</strong>nação <strong>de</strong> operações <strong>de</strong> junção é importante para reduzir o tamanho<br />

dos resultados intermediários.<br />

π nome_cliente (( σ cida<strong>de</strong>_agência = “Brooklyn” (agência)) |X| conta |X| <strong>de</strong>positante)<br />

<br />

Po<strong>de</strong>ríamos executar conta |X| <strong>de</strong>positante primeiro e, então, fazer a junção do<br />

resultado com:<br />

σ cida<strong>de</strong>_agência = “Brooklyn” (agência).<br />

<br />

Entretanto, conta |X| <strong>de</strong>positante provavelmente é uma relação gran<strong>de</strong>, já que contém<br />

uma tupla para cada conta. Em contrapartida,<br />

é, provavelmente, uma relação pequena.<br />

σ cida<strong>de</strong>_agência = “Brooklyn” (agência) |X| conta<br />

<br />

Para confirmar, observe que, como o banco tem um gran<strong>de</strong> número <strong>de</strong> agências<br />

amplamente distribuídas, é provável que apenas uma fração pequena dos clientes do<br />

banco tenha conta em agências localizadas no Brooklyn. Assim, a expressão prece<strong>de</strong>nte<br />

resulta em uma tupla para cada conta mantida em uma agência localizada no Brooklyn.<br />

Então, a relação temporária que precisa ser armazenada é menor que a que se obteria<br />

fazendo primeiro conta |X| <strong>de</strong>positante.


<strong>Otimização</strong> Heurística<br />

<br />

Uma árvore <strong>de</strong> consulta po<strong>de</strong> ser transformada passo a<br />

passo em outra árvore <strong>de</strong> consulta mais eficiente.<br />

<br />

Entretanto é preciso assegurar que os passos <strong>de</strong><br />

transformação sempre levem a uma árvore <strong>de</strong> consulta<br />

equivalente.<br />

<br />

Determinadas regras <strong>de</strong> transformação preservam essa<br />

equivalência.


Algoritmo <strong>de</strong> <strong>Otimização</strong> Algébrica<br />

<br />

<br />

Passo1:<br />

A regra 1, ao ser usada, quebra quaisquer<br />

operações SELECT com condições conjuntivas em<br />

uma cascata <strong>de</strong> operações SELECT, permitindo<br />

um maior grau <strong>de</strong> liberda<strong>de</strong> para transferir<br />

operações SELECT para ramos diferentes e<br />

abaixo na árvore.<br />

Passo2:<br />

Usando as regras 2, 4, 6, e 10 relativas à<br />

comutativida<strong>de</strong> do SELECT com outras operações,<br />

move cada operação SELECT o mais longe para<br />

baixo na árvores, que forem permitido pelos<br />

atributos envolvidos na condição <strong>de</strong> seleção.


Algoritmo <strong>de</strong> <strong>Otimização</strong> Algébrica<br />

Passo 3:<br />

Usando as regras 5 e 9, relativas à comutativida<strong>de</strong> e<br />

associativida<strong>de</strong> <strong>de</strong> operações binárias, rearraja os<br />

nós folhas da árvore utilizando o seguinte critério:<br />

<br />

Posiciona as relações do nó folha com operações <strong>de</strong><br />

SELECT mais restritivas, <strong>de</strong> forma que elas possam ser<br />

executadas o quanto antes.


Algoritmo <strong>de</strong> <strong>Otimização</strong> Algébrica<br />

Passo 4:<br />

Usando a regra 12, combina uma operação <strong>de</strong><br />

PRODUTO CARTESIANO com uma operação<br />

SELECT subseqüente na árvore, gerando uma<br />

operação JOIN se a condição representa uma<br />

condição <strong>de</strong> junção.<br />

Passo 5:<br />

Usando as regras 3, 4, 7 e 11, relativas à cascata <strong>de</strong><br />

PROJECT e à comutação <strong>de</strong> PROJECT com outras<br />

operações, quebra e transfere as listas <strong>de</strong> atributos<br />

<strong>de</strong> projeção para baixo na árvore.


Algoritmo <strong>de</strong> <strong>Otimização</strong> Algébrica<br />

Passo 6:<br />

I<strong>de</strong>ntifica subárvores que representam grupos <strong>de</strong><br />

operações que po<strong>de</strong>m ser executadas por um único<br />

algoritmo (execuções em pipeline).<br />

Como exemplo, consi<strong>de</strong>re a consulta:<br />

select unome<br />

from Empregado, Trabalha_Em, Projeto<br />

where pnome = ‘Aquarius’ and pnumero = pno and<br />

essn = ssn and datanasc > ’31-12-1957’;


Exemplo:<br />

Passos na conversão <strong>de</strong> uma<br />

árvore <strong>de</strong> consulta durante a<br />

otimização heurística. (a) Árvore<br />

<strong>de</strong> consulta inicial (canônica) para<br />

a consulta. (b) Transferência das<br />

operações SELECT para baixo na<br />

árvore <strong>de</strong> consulta. (continua)


Exemplo:<br />

Passos na conversão <strong>de</strong> uma<br />

árvore <strong>de</strong> consulta durante a<br />

otimização heurística. (c)<br />

Aplicação, em primeiro lugar, da<br />

operação SELECT mais restritiva.<br />

(d) Substituindo PRODUTO<br />

CARTESIANO e SELECT por<br />

operações JOIN.


Exemplo:<br />

Passos na conversão <strong>de</strong> uma<br />

árvore <strong>de</strong> consulta durante a<br />

otimização heurística. (e)<br />

Transferência das operações<br />

PROJECT para baixo na árvore<br />

<strong>de</strong> consulta.


A Escolha <strong>de</strong> Planos <strong>de</strong> Avaliação<br />

<br />

<br />

A geração <strong>de</strong> expressões é apenas parte do processo<br />

<strong>de</strong> otimização <strong>de</strong> consultas.<br />

Um plano <strong>de</strong> avaliação <strong>de</strong>fine exatamente qual algoritmo<br />

será usado para cada operação e como a execução das<br />

operações é coor<strong>de</strong>nada.<br />

π nome_cliente<br />

(classificar para remover duplicatas)<br />

|X| (hash-junção)<br />

|X| (merge_junção) <strong>de</strong>positante<br />

σ cida<strong>de</strong>_agência = Brooklyn<br />

σ saldo < 1000<br />

σ(use o índice 1) (use a varredura linear)<br />

agência<br />

conta


Interação <strong>de</strong> Técnicas <strong>de</strong> Avaliação<br />

<br />

<br />

<br />

<br />

Um modo <strong>de</strong> escolher um plano <strong>de</strong> avaliação para uma expressão <strong>de</strong><br />

consulta é simplesmente escolher o algoritmo mais barato para avaliar<br />

cada operação. E, olhando para os níveis da árvore, escolhe-se qualquer<br />

or<strong>de</strong>namento para a execução das operações, <strong>de</strong>s<strong>de</strong> que as operações<br />

nas camadas mais baixas da árvore sejam executadas antes das<br />

operações nas camadas mais altas.<br />

Entretanto, essa estratégia po<strong>de</strong> não ser a melhor. Embora uma mergejunção,<br />

sob certas condições, possa ser mais cara que uma hash-junção,<br />

ela consegue prover um resultado classificado que torna mais barata a<br />

avaliação <strong>de</strong> uma operação posterior (como uma eliminação <strong>de</strong> duplicatas<br />

ou uma outra merge-junção).<br />

Para escolher o melhor algoritmo global, se <strong>de</strong>ve consi<strong>de</strong>rar até mesmo os<br />

algoritmos que não são os melhores para as operações individuais.<br />

Abordagens para escolha do melhor plano <strong>de</strong> avaliação:<br />

Baseada no custo <strong>de</strong> todos os planos;<br />

Heurística.


<strong>Otimização</strong> Baseada em Custo<br />

<br />

O otimizador baseado no custo gera uma faixa <strong>de</strong> planos <strong>de</strong><br />

avaliação a partir <strong>de</strong> uma <strong>de</strong>terminada consulta usando as regras<br />

<strong>de</strong> equivalência e escolhe aquele <strong>de</strong> menor custo.<br />

<br />

Para uma consulta complexa, o número <strong>de</strong> planos diferentes por ser<br />

muito gran<strong>de</strong>.<br />

<br />

Diferentes técnicas po<strong>de</strong>m ser usadas para diminuir o número <strong>de</strong><br />

planos a serem avaliados:<br />

Quando se examina os planos para uma expressão, é possível<br />

terminar após examinar apenas uma parte da expressão, se for<br />

<strong>de</strong>terminado que o plano mais barato para aquela parte já está<br />

mais caro que a avaliação mais barata para uma expressão<br />

completa já examinada.


<strong>Otimização</strong> Heurística<br />

Regras heurística são utilizadas para<br />

transformar consultas da álgebra relacional;<br />

No otimizador heurístico, a estratégia mais<br />

eficiente para cada operação é escolhida.


Estrutura dos Otimizadores <strong>de</strong> Consulta<br />

<br />

<br />

<br />

<br />

Na prática, a maioria dos otimizadores <strong>de</strong> consultas combinam<br />

estratégias baseadas em custo com estratégias heurísticas.<br />

Alguns SGBDs consi<strong>de</strong>ram a probabilida<strong>de</strong> <strong>de</strong> já haver no<br />

buffer a página que contém o dado que se está precisando<br />

(isso é mais um dado estatístico e po<strong>de</strong> resultar em estimativas<br />

<strong>de</strong> custos menores).<br />

É possível usar a estratégia heurísticas <strong>de</strong> dividir as consultas<br />

em sub-consultas que não utilizem mais <strong>de</strong> duas tabelas.<br />

Transforma consultas em SQL em outras consultas em SQL<br />

que utilizam junções on<strong>de</strong> for possível facilita a transformação<br />

da consulta em SQL em uma consulta em álgebra relacional.


<strong>Otimização</strong> em PostgreSQL<br />

<br />

Seguem alguns breves comentários sobre otimização e<br />

<strong>de</strong>sempenho em PostgreSQL.<br />

<br />

Para otimização e <strong>de</strong>sempenho, PostgreSQL utiliza-se<br />

dos comandos vacuum, analyze e explain.


<strong>Otimização</strong> em PostgreSQL<br />

VACUUM O comando Vacuum tanto recupera<br />

espaço em disco, quanto otimiza o <strong>de</strong>sempenho do<br />

banco e previne contra perda <strong>de</strong> dados muito antigos,<br />

<strong>de</strong>vido ao recomeço do ID das transações. Portanto,<br />

<strong>de</strong>ve ser utilizado constantemente, pois também<br />

atualiza as estatísticas dos dados utilizados pelo<br />

planejador <strong>de</strong> comandos.<br />

Na linha <strong>de</strong> comando:<br />

vacuumdb -faze ou vacuumdb -fazq.


<strong>Otimização</strong> em PostgreSQL<br />

<br />

Exemplo <strong>de</strong> uso do vacuum:<br />

Em uma tabela:<br />

VACUUM VERBOSE ANALYZE nometabela;<br />

Em um banco <strong>de</strong> dados completo:<br />

Somente VACUUM ou VACUUM FULL ANALYZE;<br />

<br />

Recomendações:<br />

Para a maioria das instalações executar o comando VACUUM<br />

ANALYZE para todo o banco <strong>de</strong> dados, <strong>de</strong> vez em quando, em horário<br />

<strong>de</strong> pouca utilização.<br />

Quando for excluída a maioria dos registros <strong>de</strong> uma tabela, sugere-se a<br />

execução do comando VACUUM FULL. Contudo, este comando gera<br />

um forte bloqueio nas tabelas em que é executado.


<strong>Otimização</strong> em PostgreSQL<br />

ANALYZE O comando ANALYZE coleta estatísticas<br />

sobre o conteúdo das tabelas do banco <strong>de</strong> dados e armazena os<br />

resultados na tabela do sistema pg_statistic. Posteriormente, o<br />

planejador <strong>de</strong> comandos utiliza estas estatísticas para ajudar a<br />

<strong>de</strong>terminar o plano <strong>de</strong> execução mais eficiente. Caso estas<br />

estatísticas não sejam atualizadas com freqüência, po<strong>de</strong> ser<br />

comprometido o <strong>de</strong>sempenho do banco <strong>de</strong> dados, por uma<br />

<br />

escolha errada do plano <strong>de</strong> execução dos comandos.<br />

Normalmente, operações DELETE ou UPDATE não removem<br />

os registros automaticamente (somente após a execução do<br />

vacuum isso acontece).


<strong>Otimização</strong> em PostgreSQL<br />

No PostgreSQL, po<strong>de</strong> ser utilizado o comando<br />

explain para ver o plano (conjunto executável <strong>de</strong><br />

instruções) criado pelo sistema para qualquer<br />

comando.<br />

O comando explain traz informações sobre custo,<br />

como tamanho da tupla, custo estimado <strong>de</strong> execução,<br />

entre outros.<br />

Exemplo <strong>de</strong> uso do explain:<br />

EXPLAIN SELECT * FROM NOMETABELA;


<strong>Otimização</strong> em PostgreSQL<br />

EXPLAIN ANALYZE Executa a consulta e<br />

mostra o tempo real acumulado <strong>de</strong>ntro <strong>de</strong> cada<br />

nó do plano <strong>de</strong> execução, junto com os custos<br />

estimados que o comando explain simples<br />

mostraria.


Referências Bibliográficas<br />

<br />

Sistemas <strong>de</strong> Banco <strong>de</strong> Dados. (Cap. 12) Abraham<br />

Silberchatz, Henry F. Korth e S. Sudarshan. 3ª Edição.<br />

Makron Books, 1999.<br />

<br />

Sistemas <strong>de</strong> Banco <strong>de</strong> Dados. (Cap. 15) Ramez<br />

Elsmari, Shamkant B. Navathe. 4ª Edição. Pearson<br />

Addison Wesley, 2005.<br />

<br />

Manuais do PostgreSQL.

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!