Você está na página 1de 42

UNIVERSIDADE FEDERAL DE PERNAMBUCO

GRADUAO EM

CINCIA DA COMPUTAO

CENTRO DE INFORMTICA

ANLISE

DE FORMAS DE OTIMIZAO
DE CONSULTAS

TRABALHO DE GRADUAO

Aluna:

Alexsandra Cassiano Alves da Silva (acas2@cin.ufpe.br)

Orientadora: Ana Carolina Salgado (acs@cin.ufpe.br)

Resumo
Com o crescimento e popularizao da internet esto sendo desenvolvidos, cada vez
mais sistemas para Web. Alm disso, o nmero de empresas sendo informatizadas cresce a cada
dia. Todas estas novas aplicaes necessitam de uma forma eficiente de armazenamento e
recuperao de dados. Para isso se faz necessrio o uso de um bom SGBD e de sistemas que
usem os recursos deste SGBD eficientemente. O volume de informaes com os quais estes
sistemas lidam vem aumentando constantemente e, alm do mais, estas informaes muitas
vezes so armazenadas remotamente, o que torna o tempo de resposta das aplicaes um fator
decisivo para o sucesso das mesmas.
O objetivo deste trabalho investigar diferentes formas de se estruturar consultas
possibilitando otimizar a velocidade de execuo das mesmas, bem como a anlise da
influncia de ndices, quando e como estes devem ser usados, j que ndice uma estrutura de
banco de dados que tem forte influncia sobre a velocidade de acesso a informaes.
Isto ser feito atravs de uma pesquisa onde sero analisados operadores SQL, funes
especficas do SGBD, criao e manipulao de ndices. O SGBD Oracle foi escolhido para o
desenvolvimento do trabalho pois ele um dos SGBDs mais usados no mercado.

ndice
1. Introduo
1.1. Onde esto os problemas de performance em um sistema
tpico?
1.2. Por que se preocupar?
1.3. Objees comuns a otimizao
1.4. Quando o SQL deve ser otimizado?
1.5. Outros Fatores que tambm melhoram a performance
1.6. Usando Hints para Otimizao
1.7. Escolhendo a estratgia de otimizao
1.8. O Banco de Dados de exemplo

3
3
4
5
6
7
7
8
10
10

2. Princpios e Otimizao de ndice


2.1. O que um ndice?
2.2. Tipos de Indices
2.2.1. B* - Tree ndice
2.2.2. ndice Agrupado
2.2.3. Bitmapped indices
2.2.4. Index Sobre Tabelas
2.3. Full Table Scan e ndice Lookups
2.4. Evitando Full Table Scan Acidental

11
11
11
12
16
16
17
20
20

3. Otimizando Juno e Subconsultas


3.1. Tipos de Juno
3.2. Escolhendo o melhor mtodo de juno
3.3. Escolhendo a melhor ordem das tabelas para a juno
3.4. Outer Join
3.5. Consulta Hierrquica
3.6. Subconsulta Simples
3.7. Subconsultas envolvendo o operador IN
3.8. Subconsulta Correlacionadas
3.9. Subconsulta Correlacionada usando EXISTS

23
24
24
28
29
30
32
33
33
35

4. Otimizando Ordenao e Agrupamento

40

5. Concluso

42

6. Referncias

43

1. Introduo
Com o crescimento e popularizao da internet esto sendo desenvolvidos, cada vez
mais sistemas para Web, alm disso o nmero de empresas sendo informatizadas cresce a cada
dia. Todas estas novas aplicaes necessitam de uma forma eficiente de armazenamento e
recuperao de dados. Para isso se faz necessrio o uso de um bom SGBD e de sistemas que
usem os recursos deste SGBD eficientemente. O volume de informaes com os quais estes
sistemas lidam vem aumentando constantemente e, alm do mais, estas informaes muitas
vezes so armazenadas remotamente, o que torna o tempo de resposta das aplicaes um fator
decisivo para o sucesso das mesmas.
Os requisitos gerais de um sistema variam de aplicao para aplicao. Em aplicaes
de data warehouse a performance e o gerenciamento de uma grande quantidade de dados so
fatores importantes. Em aplicaes que processam transaes on-line (OLTP), transaes,
performance de consultas e uma alta disponibilidade do sistema so requisitos muito
importantes. Em aplicaes que gerenciam dados no estruturados, tal como um sistema de
recuperao de informaes, a habilidade de gerenciar e acessar rapidamente estes dados
complexos e no estruturados muito importante.
evidente que a velocidade de acesso a dados e o tempo de resposta de consultas um
fator decisivo no s para estes tipos de aplicaes, mas tambm para sistemas convencionais,
o usurio atual no est mais disposto a uma longa espera para conseguir as informaes que
deseja. Mesmo que a potncia das mquinas atuais j facilitem bastante no se deve deixar
aplicaes dependentes do hardware em uso, assim se faz necessrio a otimizao de consultas
de forma independente do hardware.
O SGBD Oracle oferece uma variedade de estratgias de indexao de dados e formas
de otimizao de consultas que auxiliam projetistas e desenvolvedores a atingirem
determinados requisitos de performance. Por este SGBD ser um dos mais eficientes e de
grande uso no mercado esta pesquisa ser baseada no mesmo. O que no impede que muitos
dos conceitos vistos aqui sejam aplicados a outros SGBDs.
1.1 Onde esto os problemas de performance em um sistema tpico?
Vrios fatores influenciam na velocidade de execuo de uma consulta, desde a
configurao do SGBD granularidade dos dados armazenados. Dentre estes fatores temos a
forma como as consultas so estruturadas, ou seja, problemas no programa, sendo este o fator
de maior influncia na performance, representando cerca de sessenta por cento dos problemas
de performance de um sistema tpico, o que de se esperar pois todas as funcionalidades que
recuperam dados o fazem atravs de consultas. Um outro fator de grande influncia o
projeto do banco de dados, aqui se enquadrando a estrutura do banco e a indexao do
mesmo, representando cerca de vinte por cento dos problemas de performance. Dezoito por
cento atribudo a problemas no banco, tal como parmetros de configurao, etc. e mais ou
60
menos dois
por cento atribudo a problemas relacionados ao sistema operacional, como
Onde normalmente
mostra a figura 1.1. bom notar que as percentagens mostradas
no necessariamente se
50
existe problemas de
aplicam a 100% dos sistemas [2].
performance
Nos
40 outros tpicos deste trabalho sero detalhados os fatores de maior influncia na
performance das aplicaes Oracle, sendo nesta sesso introdutria mencionados alguns outros
fatores, tambm
ser discutido nesta sesso porque to necessrio a otimizao, quando
30
deve-se otimizar uma consulta SQL, aspectos da base de dados utilizada no trabalho, etc.
20
10
0

Programa

Projeto

BD

SO

Figura 1.1: Localizao Tpica dos Problemas de Performance

No otimizada(bottleneck)
No otimizada(exponencial)

No otimizada(linear)

Aplicaes otimizadas

Figura 1.2:
1.2 Por que se preocupar?
Melhorar consultas nem sempre uma tarefa fcil e as vezes pode consumir mais
tempo do que escrever e testar o SQL, e verdade que os SGBDs Oracle j vem com um
otimizador, parte do Oracle responsvel pela otimizao de consultas que faz grande parte do
trabalho. Ento porque se importar?
Nenhum otimizador perfeito ao ponto de poder substituir completamente um DBA ou
um desenvolvedor experiente, ele um programa e como tal est suscetvel a falhas, assim um
desenvolvedor bem treinado pode prever e resolver problemas sem recorrer ao DBA. Outros
fatos tambm influenciam neste processo, por exemplo assegurar a escalabilidade das
aplicaes. Sistemas bem otimizados respondem, na medida do possvel, de maneira similar
variao de nmero de usurios e/ou ao volume de dados, evitam upgrades de hardware, j
que seu tempo de resposta independe da capacidade do hardware. Um sistema no
otimizado pode requerer uma srie escalvel de upgrades, entre outros fatores[2].
Uma aplicao bem otimizada ir continuar a responder bem mesmo com o aumento de
usurios ou volume de dados. Uma aplicao mal otimizada ir apresentar degradao de
4

performance, podendo esta degradao ser linear, exponencial ou abrupta. Como mostra a
Figura 1.2 [1].
1.3 Objees comuns a otimizao
Escrever consultas que funcionem bem mais fcil que escrever consultas eficientes,
bem otimizadas. Para se escrever consultas eficientes se faz necessrio um bom conhecimento
da estrutura do banco de dados, para que se possa fazer uso de estruturas existentes, tal como
ndices, e tambm encontrar a melhor forma de se realizar a consulta pois dependendo da
estrutura do banco uma mesma consulta pode ser realizada de vrias maneiras. Por este
esforo extra necessrio e tambm pelo o tempo de desenvolvimento das aplicaes estar
sendo cada vez mais curto, algumas posturas em relao a otimizao so comuns:

O otimizador Oracle ir resolver a otimizao para mim.


Como visto anteriormente, o otimizador no perfeito e o desenvolvedor deve
assegurar que a consulta ir responder bem em qualquer situao, o otimizador no
tem conhecimento da natureza e da massa de dados. Assim, uma consulta que
responde bem com uma tabela de mil registros pode simplesmente parar quando a
tabela vier a ter 10 milhes registros.

Otimizao de SQL no minha rea


uma atitude perigosa achar que a performance das consultas escritas no sejam de
responsabilidade de quem as criou, pois desenvolvedores de front-end simplesmente
usam o que est implementado assumindo que tudo esteja correto e funcionando
como deveria. Uma consulta SQL pode ter impacto sobre toda uma aplicao e se
voc a escreveu tem responsabilidade sobre ela e isso inclui performance.

Eu irei escrever, algum a otimiza pra mim.


Esta outra atitude bastante errada, deixar a otimizao de uma consulta SQL
escrita por voc a cargo de outra pessoa, possivelmente um DBA. Esta uma
atitude bastante perigosa pois a pessoa pode no ter tempo suficiente para esta
atividade, ficando sem ser feita, ou ir gastar tempo extra entendendo a consulta, j
que no foi ela quem a escreveu, para ento fazer alteraes, podendo estas
influenciar na semntica do resultado.

Depois eu a otimizo
O problema com esta atitude est no fato de que quanto mais se espera mais pode
ser complicado fazer alteraes na consulta SQL, resolver problemas de software
sempre mais fcil nas fases iniciais do ciclo de vida do desenvolvimento do
mesmo, alm de que corre-se o risco de esquecer e o problema s vir aparecer na
fase de teste da aplicao, ou pior ainda, quando o sistema j estiver implantado.

No tem mais o que otimizar, no posso gastar mais tempo com isso.
Algumas aplicaes requerem rapidez no seu desenvolvimento, e algumas tarefa
necessrias acabam sendo consideradas suprfluas. Cometer este erro com a
otimizao do comando SQL de uma consulta pode ser fatal, a falha na
implementao de comandos eficientes pode levar a upgrades desnecessrios de
hardware, perda de produtividade dos usurios do sistema, insatisfao dos
usurios finais e freqentemente ao cancelamento de contratos de projetos de
software.
5

A falha de no se otimizar as aplicaes no incio do desenvolvimento das mesmas


normalmente leva a um maior esforo para que se obtenha um resultado semelhante quando a
otimizao feita nas fases finais do desenvolvimento. Quase sempre, sistemas no otimizados
precisam de hardware mais caros para rodar to bem quanto um sistema otimizado. O que
poderia ser resolvido em poucas semanas se considerado no incio do desenvolvimento, pode
levar meses quando tratado nas fases finais e nem sempre se consegue o mesmo resultado.
1.4 Quando a consulta deve ser otimizada?
Idealmente, uma consulta SQL deve ser otimizada quando ele escrita. A medida que
se avana no ciclo de vida do desenvolvimento de um software, o custo dotimizao aumenta e
as melhorias de performance que poderamos esperar diminuem. Existem vrios fatores que
contribuem para isto:

Certos aspectos das aplicaes se tornam impossvel de mudar sem uma grande reimplementao e/ou re-projeto. Por exemplo, a fase de projeto de uma aplicao de
banco de dados forma a base para toda ela, mudana em uma estrutura no modelo
de dados na fase inicial do desenvolvimento certamente no ter grandes
implicaes, mas se esta mudana for realizada nas fases finais pode implicar num
grande esforo para se ajustar toda aplicao ao novo modelo de dados.

Quando se otimiza-se uma consulta a medida que ela escrita s preciso test-la
uma vez, mas se a otimizao ocorre aps uma fase de teste, todos os testes devem
ser repetidos para assegurar a estabilidade do sistema. Alm do mais, ser
necessrio um esforo maior pois quando a consulta est sendo escrita todas as
estruturas necessrias e a lgica usada esto vivas na memria, mas otimizar a
consulta depois de algum tempo ir requerer um tempo extra para que se possa
relembrar o propsito lgico da mesma.

Uma vez que um sistema entra num ambiente de produo existem restries que
dificultam o processo. Por exemplo, o sistema no pode ficar indisponvel por
muito tempo, alteraes nas estruturas de dados ir ocasionar grandes transtornos,
at mesmo os desenvolvedores podem sair prejudicados, tendo que minimizar os
problemas causados recuperando o sistema em finais de semana ou a noite, isso se
o sistema puder ser recuperado facilmente.

Na Figura 1.3 mostrado um grfico do custo X benefcio da otimizao de uma


consulta SQL ao longo dos vrios estgios do ciclo de vida do desenvolvimento de software
[2].
A partir do que foi exposto, evidente que a otimizao de um sistema deve ser
introduzida to cedo quanto possvel no desenvolvimento de um sistema e que fazer isto bem
mais econmico e eficiente.
uma prtica comum problemas de performance serem ignorados durante o
desenvolvimento de software, at porque na maioria das vezes o ambiente de desenvolvimento
e de produo no refletem a mesma realidade. Nem sempre os desenvolvedores tm
experincia e tempo suficiente para carregar as bases de dados com uma carga que reflita a
realidade da aplicao, dessa forma infelizmente alguns problemas acabam escapando da fase
de testes e s aparecem quando o sistema j est em produo.

Figura 1.3:

1.5 Outros Fatores que tambm melhoram a performance


Outros fatores tambm auxiliam na otimizao de um sistema, alm do uso de ndice e
da otimizao de SQL, os quais sero vistos em detalhe.
A alocao de memria para o banco de dados pode ter grande influncia, alocar
memria demais ser um desperdcio de recursos e de menos pode causar at um deadlock.
Otimizar a alocao de memria para aplicaes Oracle significa configurar os
parmetros init.ora (parmetros de inicializao) corretamente. Os parmetros cruciais so
DB_BLOCK_BUFFERS, SHARED_POOL_SIZE, SORT_AREA_SIZE, DB_BLOCK_SIZE.
Setar algum desses parmetros muito alto ou muito baixo ir fazer o sistema rodar com baixa
performance [2].
Uma vez que se tenha memria suficiente alocada, deve-se assegurar que esta seja
usada corretamente, as informaes mais importantes devem ser buscadas da memria e
permanecer l. Oracle permite que uma tabela seja criada para permanecer na memria,
utilizando o parmetro CACHE, esta propriedade pode ser alterada conforme desejado. Alm
disso o resultado de uma consulta tambm pode ser mantido na memria utilizando-se o hint
CACHE. Hints so instrues que podem ser includas no SQL para instruir ou guiar o
otimizador, usando hints o usurio pode especificar a ordem da juno, tipo do caminho de
acesso aos dados, ndice a ser usado e outras instrues.
1.6 Usando Hints para Otimizao
O otimizador no perfeito, contudo existem hints que podem ser usadas para mudar a
forma como o otimizador se comporta. Eventualmente se encontra uma consulta que requer
uma ateno especfica. Quando uma consulta assim encontrada se pode tomar vantagem dos
hints que Oracle oferece para otimizar uma consulta individual. Abaixo est a sintaxe de alguns
hints:
7

Full para forar um full table scan:


select /*+ FULL(table_name) */ column1, column2 ...
Index para forar um acesso por ndice:
select /*+ INDEX(table_name index_name1 index_name2...) */
Ordered para forar que as tabelas sejam usadas na ordem que esto no FROM:
select /*+ ORDERED */ column1, column2 ...
from table1, table2
USE_NL Isto fora o uso de NESTED LOOPS. A tabela listada no hint ser
usada como tabela interna do NESRED LOOP.
Select /*+ Use_NL(table table) */
1.7 Escolhendo a estratgia de otimizao
Para quase todos os comandos SQL existe mais de uma forma do Oracle recuperar as
linhas requeridas. Quando o Oracle faz o parse de um comando SQL ele deve decidir qual
abordagem ser mais rpida. O processo de determinar este caminho timo referenciado
como otimizao de consulta.
Otimizao de consulta aplicado a todas as consultas e a qualquer outro comando
(por exemplo UPDATE, INSERT, DELETE) que contm uma consulta ou contm uma
clusula WHERE.
A parte do Oracle que realiza a otimizao de consultas chamado de otimizador. O
otimizador Oracle suporta duas abordagens para a otimizao de consultas:
O otimizador baseado em regra que o mais antigo dos dois otimizadores e surgiu
com o Oracle RDBMS. Este otimizador toma decises baseado em um conjunto de
regras e no ranking dos vrios caminhos de acesso. O otimizador baseado em regra no
se preocupa com volume de dados e nem tem como tomar decises baseadas nestes
dados. Por exemplo, um otimizador baseado em regra ir sempre preferir uma procura
por ndice a um full table scan. Contudo, ele no pode distinguir entre um full table
scan de uma tabela com duas linhas e uma tabela com dois milhes de linhas.
O otimizador baseado em custo foi introduzido com o Oracle 7. Ele incorpora vrios
comportamentos do otimizador baseado em regra, mas tem a vantagem de ser capaz de
tomar vantagem de informaes estatsticas sobre o volume e a distribuio dos dados
em tabelas e ndices. Por isso este otimizador pode distinguir entre uma tabela de duas
linhas e uma tabela de dois milhes de linhas, e pode gerar diferentes planos de
execuo para cada uma.
At aqui o otimizador baseado em custo parece ser a melhor opo, mas algumas
consideraes devem ser tomadas antes de se optar por um ou outro.
Alm do fato de o otimizador baseado em custo ser relativamente novo no mercado,
muitos sistemas continuam utilizando uma abordagem baseada em regra, e existem vrias
razes para isso[5]:
As verses iniciais do otimizador baseado em custo continham deficincias
significantes e uma melhor performance freqentemente s era conseguida
utilizando-se o otimizador baseado em regra.

Converter sistemas existentes para o otimizador baseado em custo seria uma tarefa
bastante custosa, uma vez que todos os comandos SQL teriam que ser revistos,
para tomar vantagem da otimizao baseada em custo.
Desenvolvedores e DBAs j vinham usando o otimizador baseado em regra e
utilizar o baseado em custo iria requerer treinamento e familiarizao.
O plano de execuo de um otimizador baseado em custo pode mudar quando os
dados mudam. Isto o torna menos previsvel que o baseado em regra. Isto tambm
significa que consultas desenvolvidas em um ambiente de desenvolvimento pequeno
ou mdio podero ter um comportamento diferente em um grande ambiente de
produo.
O otimizador baseado em custo necessita que todas as tabelas que ele precisa para
tomar decises estejam analisadas, caso contrrio ele poder tomar decises
erradas. Oracle fornece um comando para que isso seja realizado, com diferentes
opes de nvel de detalhes, esta operao pode levar bastante tempo e se torna
uma manuteno constante a ser feita no sistema.
Apesar do que foi exposto , o otimizador baseado em custo uma deciso correta para
a maioria dos novos projetos e uma opo vlida de migrao para a maioria dos sistemas
existentes. A otimizao baseada em custo representa o futuro da otimizao de consultas
Oracle, enquanto o otimizador baseado em regra ser descartado em algum tempo durante a
vida do Oracle verso 8. Melhorias no otimizador baseado em custo tm sido feitas em cada
release do Oracle, enquanto o baseado em regra est praticamente inalterado desde o primeiro
release do Oracle 7, e agora o otimizador baseado em custo quase sempre escolhe um plano de
execuo que to bom ou melhor que aquele do otimizador baseado em regra[10], quando
no se pode usar hints para ajustar o plano de execuo.
Quando se escolhe a estratgia de otimizao o otimizador deve ser configurado. Para
isso, deve-se configurar o otimizador. Para se utilizar a otimizao baseada em custo ele
configurado como CHOOSE, onde caso esteja disponvel informaes estatsticas sobre as
tabelas envolvidas na otimizao ela ser baseada em custo, caso contrrio sero utilizadas
regras para definir o plano de execuo. Para a otimizao baseada em regra o otimizador deve
ser configurado como RULE, assim ele sempre utilizar regra, independente de existir
informaes estatsticas sobre a tabelas ou no.
O otimizador baseado em custo pode tornar o processo de otimizao mais fcil, j que
ele normalmente escolhe o melhor ndice (o mais seletivo) de todos os disponveis e escolhe
uma boa driving table. Mas criar um ndice, caso ele esteja faltando, rescrever consultas mal
formuladas, seja qual for a abordagem de otimizao, no pode ser feito pelo otimizador.
Ento, continua sendo uma tarefa de quem escreveu a consulta assegura que ela est
funcionando como deve.
Neste trabalho, quando necessrio, ser citado o funcionamento especfico de uma
consulta com um otimizador ou outro, sempre que se falar em quantidade de dados na criao
de histogramas para que uma consulta funcione corretamente est subentendido que o
otimizador baseado em custo.
Vrios testes utilizando-se as duas estratgias de otimizao foram feitos, para isso foi
usado a ferramenta PL-SQL Developer e atravs dele foi analisado o plano de execuo e a
velocidade de execuo das consultas. Tambm foram utilizadas outros processos de anlise
fornecidos pela Oracle.
1.8 O Banco de Dados de exemplo
No decorrer desta pesquisa foi utilizado um banco de dados exemplo cujo modelo est
abaixo, alm deste foi utilizado um banco de dados de um sistema real para otimizao de
9

consultas reais com grande massa de dados, o modelo deste banco no ser mostrado aqui por
questo de sigilo da aplicao, mas os resultados obtidos esto includos no relatrio.
DEPARTMENTS

_______________________________________________________

DEPARTMENT ID

NUMBER

DEPARTMENT_NAME VARCHAR2(40)
MANAGER_ID
NUMBER
LOCATION
VARCHAR2(40)

COMMENTS

________________________________________________________

COMMENT ID

NUMBER

COMMENT NUMBER NUMBER


COMMENT
VARCHAR2(80)

PRODUCTS

________________________________________________________

PRODUCT ID
EMPLOYEES

__________________________________________________

EMPLOYEE ID

NUMBER

PRODUCT_DESCRIPTION VARCHAR2(80)
NORMAL_VALUE
NUMBER

NUMBER

SURNAME
VARCHAR2(40)
FIRSTNAME
VARCHAR2(40)
ADDRES1
VARCHAR2(40)
ADDRESS2
VARCHAR2(40)
ZIPCODE VARCHAR2(6)
DATE_OF_BIRTH DATE
PHONENO
VARCHAR2(12)
MANAGER_ID
NUMBER
SALARY
NUMBER
STATUS
VARCHAR2(9)
DEPARTMENT_ID NUMBER
COMMENT_ID
NUMBER

SALES

CUSTOMERS

________________________________________________________

CUSTOMER ID

NUMBER

COMMET_LINE
VARCHAR2(40)
CUSTOMER_NAME
VARCHAR2(40)
CUSTOMER_SURNAME VARCHAR2(40)
CUSTOMER_FIRSTNAME VARCHAR2(40)
ZIPCODE
VARCHAR2(6)
DATE_OF_BIRTH
DATE
PHONENO
VARCHAR2(12)
MANAGER_ID
NUMBER
SALES_REP_ID
NUMBER
COMMENT_ID
NUMBER
STATUS
VARCHAR2(9)
PROCESS_FLAG
NUMBER

__________________________________________

CUSTOMER ID

NUMBER

PRODUCT ID
SALES_DATE
QUANTITY
SALES_VALUE

NUMBER
DATE
NUMBER
NUMBER

10

Princpios e Otimizao de ndice

Oracle fornece vrios esquemas que provem eficincia e rpido acesso a dados,
atravs de tipos diferentes de ndices que devem ser usados de acordo com o objetivo.
Desenvolvedores ou administradores de banco de dados devem selecionar a estratgia de
indexao que melhor se adequar a tabela em uso na aplicao. comum haver mais de um
ndice sobre uma tabela de forma a melhorar a performance para uma variedade de consultas
ou caminhos de acesso.
Oracle8 prov o maior conjunto de funcionalidades de indexao de qualquer DBMS
do mercado [4]. Pela completa integrao desta tecnologia com o otimizador Oracle, o acesso
rpido aos dados transparentemente assegurado na maioria das situaes. O otimizador tem
conhecimento dos vrios mtodos de indexao usados sobre uma tabela e ir selecionar o
ndice que mais apropriado e eficiente para retornar os dados requisitados.
Oracle8 oferece vrios tipos diferentes de ndices e opes de armazenamento de dados
que provem benefcios de performance, disponibilidade e gerenciamento. Neste captulo ser
discutido:
B-tree ndices a estrutura de ndice default da Oracle.
ndice concatenado.
ndice agrupado.
Bitmapped ndices.
ndice sobre tabelas.
2.1 O que um ndice?
Indexes so estruturas de banco de dados associados com tabelas e so criados para
acessar dados rapidamente dentro de uma tabela. Tal como o ndice remissivo de um livro
ajuda um leitor a localizar informaes mais rapidamente que procurando a informao pgina
por pgina, um ndice sobre uma tabela prov uma forma rpida de acessar os dados da tabela.
ndices so transparentes para aplicaes e usurios pois sua presena ou ausncia no
requer alterao de qualquer SQL. Um ndice meramente um caminho rpido de acesso a
dados, ele afeta apenas a velocidade de execuo. Dado um valor que foi indexado, o ndice
aponta diretamente para a localizao das linhas contendo o valor.
O SGBD Oracle automaticamente usa e mantm o ndice depois dele ser criado. Ele
reflete as mudanas nos dados, tal como adicionar, atualizar ou apagar linhas em todos os
ndice relevantes sem que seja necessrio uma ao adicional do usurio. Isto faz com que
consideraes de performance devam ser feitas antes da criao de ndices pois o custo
adicional necessrio com a manuteno dos mesmos pode no compensar os benefcios
conseguidos na recuperao dos dados indexados. Alm disso, ndices necessitam de espao
adicional de armazenamento, sendo comum este tomar mais espao que a tabela qual ele
referencia.
2.2 Tipos de ndices
Do ponto de vista de usurio de aplicaes, ndices provem um rpido acesso a dados
de forma transparente. Do ponto de vista dos DBAs, ndices so objetos fsicos que provem o
mecanismo para acessar dados rapidamente e tambm fornecem integridade ao banco de
dados. Oracle oferece dois tipos de ndices, cada um armazenado em diferentes estruturas e
especficos para beneficiar determinados requisitos das aplicaes. Estes dois tipos so B-tree
ndices e bitmapped indices. Uma tabela tambm pode ser criada como uma index-organized
table (IOT), tambm chamado de ndice sobre tabela, ou como uma clustered table. Estas
11

duas estruturas no so ndices mas fornecem algumas das funcionalidades dos ndices, e
tambm sero discutidos adiante.
2.2.1 B* - Tree ndice
B* - Tree (Balanced Tree) ndex a estrutura de ndice padro da Oracle. A figura
2.1 mostra a estrutura de uma B* - tree.
Header block

A-K
L-Z

Branch Blocks
A-D
E-G
H-K

ADAMS
BAKER
COOK
DAVIS

EDAM
FARRAR
GOUGH

L-O
P-R
S-Z

HARRIS
JONES
KANE

LOWE
MILLER
ODEN

PRINCE
QUEEN
RICHARDS

SMITH
VALDEZ
WINTON

Leaf Blocks
Blocos de ndice so ligados em ambas as direes
Figura 2.1: Estrutura de uma B-tree ndex.
O ndice B*-Tree tem uma estrutura de rvore hierrquica. No topo da rvore est o
header block. Este bloco contm ponteiros para o branch block apropriado dado um valor
chave. O branch block normalmente ir apontar para o leaf block apropriado, ou ir apontar
para outro branch block se o ndice for grande. O leaf block contm uma lista de valores e
ponteiros (ROWIDS) para a linha apropriada na tabela.
Para o Oracle encontrar BAKER primeiro ele consulta o header block o qual informa
que valores que se iniciam com letras de A a K esto no branch block mais a esquerda.
Acessando este branch block, encontramos que valores chave de A a D esto armazenados no
leaf block mais a esquerda. Consultando-se o leaf block indicado encontramos o valor
BAKER e seu ROWID associado, o qual usado para recuperar a linha da tabela associada.
Quando um ndice acessado e o dado necessrio para satisfazer consulta reside no
leaf block, ento no necessrio utilizar o ROWID associado para recuperar a linha da
tabela, neste caso o ndice serve como a origem dos dados em vez da tabela.
Leaf blocks contm ligaes para o prximo leaf block e o anterior. Isto permite
percorrer o ndice de forma crescente ou decrescente e tambm permite consultas que utilizam
operadores < , > ou BETWEEN serem processadas usando o ndice[4].
Cada leaf block est na mesma profundidade, isto , qualquer leaf block pode ser
acessado usando o header block e um (normalmente) ou dois branch blocks.
12

B*-tree indices tem as seguintes vantagens:


Como cada leaf block est na mesma profundidade, performance bastante
presumvel . Teoricamente nenhuma linha ir precisar mais que trs ou quatro
acessos.
Oferece boa performance para tabelas grandes, tambm porque a profundidade no
mximo quatro (um header block, dois nveis de branch blocks e um nvel de leaf
block). Nenhuma linha na tabela ir necessitar mais que quatro acessos de leitura
para ser localizado. Na realidade pode ser bem menor pois o header block quase
sempre j foi lido e est na memria, e normalmente o branch block tambm.
Suporta consultas por faixa do mesmo jeito que por valor especfico. Isto possvel
por causa dos links de prximo e anterior nos leaf blocks.
B*-Tree ndice fornece um meio flexvel e eficiente de aumentar a performance de
consultas. Contudo, sua manuteno quando dados so alterados pode ser cara. Por exemplo
considere a insero de uma linha com o valor chave NIVEN dentro da tabela cujo ndice
est mostrado na figura 2.1. Para inserir a linha deve-se adicionar uma nova entrada no bloco
apontado por L-O, se existe espao livre neste bloco o custo mnimo. Mas se no existe
espao livre no bloco uma diviso do ndice requerida. Para isto ser criado um novo leaf
block e metade das entradas do leaf block anterior movida para este novo bloco. Uma nova
entrada inserida no branch block e a mesma apontar para o bloco criado, caso no tenha
espao livre no branch block ele tambm ter que ser dividido e criado um novo branch block,
e os ponteiros necessrios rearrumados.
Esta diviso de ndice uma operao cara: novos blocos devem ser alocados e
entradas de ndice movidas de um bloco para outro.
A diviso de ndice pode ser evitada aumentando o total de espao livre deixado dentro
do ndice para novas entradas. Isto definido quando o ndice criado atravs da clusula
PCTFREE do comando de criao de ndice CREATE INDEX.
Quando Criar Indices
B*-Tree Indices melhoram a performance de consultas que selecionam uma pequena
percentagem de linhas de uma tabela. Como uma dica geral, um ndice deve ser criado sobre
uma tabela onde a consulta em geral retorna cerca de dois a quatro por cento dos dados da
tabela. Esta percentagem tambm depende da verso do Oracle como mostra a figura 2.2 [2].
Alm disso a distribuio dos dados, se consultas paralelas podem ser usadas e outros fatores
devem ser considerados quando se deseja decidir sobre a criao de um ndice.
Um B-Tree ndice pode melhorar bastante o tempo de resposta quando uma aplicao
ou usurio seleciona dados onde:
Uma chave tem um valor especfico
Valores so nicos ou perto de nicos
Linhas esto dentro de uma faixa de valores, tal como um intervalo de datas.
20
Existem
certas ocasies onde um B-Tree ndice no apropriado e no ir melhorar a
18
performance de consultas. Em muitas destas situaes, tal como criar um ndice sobre uma
aplicao16de data warehouse onde a coluna indexada tem poucos valores distintos, um ndice
14 pode ser criado e melhorar bastante a performance, os benefcios de um B-Tree
bitmapped
12
ndice e exemplos
ser discutido adiante.
% de linhas
10
8
6
4
2
0

retonadas / uso
ndex

V5

V6

V7

V8

Figura 2.2: Percentagem de linhas retornadas para um uso eficiente de ndice de


acordo com a verso do Oracle

13

Seletividade de ndice
A seletividade de uma coluna ou grupo de colunas uma medida comum da
aplicabilidade de um ndice sobre esta coluna. Colunas ou ndices so seletveis se tm um
grande nmero de valores nicos ou poucos valores duplicados. Por exemplo a coluna
DATE_OF_BIRTH muito seletvel enquanto a coluna GENDER no .
ndices seletveis so mais eficientes que no seletveis porque eles apontam mais
diretamente para valores especficos. Um otimizador baseado em custo ir determinar a
seletividade dos vrios ndices disponveis para ele e tentar usar o mais seletvel.
ndice Concatenado
Um ndice concatenado um ndice que criado sobre mltiplas colunas em uma
tabela. As colunas em um ndice concatenado podem aparecer em qualquer ordem, e atravs
desta ordem definido se o ndice completo usado ou no na consulta. A vantagem de uma
chave concatenada que freqentemente ela mais seletvel que uma chave nica,
melhorando a performance do ndice pois a combinao de colunas ir apontar para um menor
nmero de linhas que ndices compostos de colunas individuais. Um ndice concatenado o qual
contm todas as colunas referenciadas na clusula WHERE do SQL ser bastante eficiente.
Se freqentemente se consulta sobre mais de uma coluna em uma tabela, ento criar um
ndice concatenado sobre estas colunas uma excelente idia. Por exemplo um ndice sobre
SURNAME e FIRSTNAME da tabela EMPLOYEE:
Create index employee_name_idx on employee(surname,firstname)
Usando tal ndice, pode-se rapidamente encontrar todos os employees que tenha
determinado surname e firstname, nesta ordem. Tal ndice ser bem mais eficiente que um
ndice sobre surname apenas, ou ndices separados sobre surname e firstname.
A figura 2.3 compara vrios caminhos de acesso para a consulta, claramente a
utilizao do ndice concatenado mais eficiente.
Ordem das Colunas em um ndice Concatenado
Se um ndice concatenado pudesse ser usado apenas quando todas as suas chaves
aparecessem na clausula WHERE de uma consulta, certamente ele teria um uso limitado.
Felizmente um ndice concatenado pode ser usado sempre que qualquer das colunas iniciais ou
tambm chamadas colunas que conduzem o ndice, forem usadas. As colunas que conduzem o
ndice so aquelas que so especificadas primeiro na definio do ndice. Por exemplo, com o
ndice concatenado criado anteriormente sobre a tabela employee (em surname e fristname), o
ndice pode ser usado para recuperar employees que combinem com determinado surname,
mas no employees com determinado firstname, neste caso um full table scan ser necessrio.
Para ficar mais claro, imagine um ndice sobre surname, firstname e date_of_birth da tabela
employee, a tabela 2.1 mostra as possibilidades de uso do ndice.
14

Nenhum ndex (Full Table Scan)


Index sobre surname apenas
Indexes separados sobre surnam e e firstnam e
Index concatenado sobre surname e firstname
0

10

15

20

25

30

35

40

45

Blocos obtidos

Figura 2.3: Comparao de vrios caminhos de acesso para a recuperao de nomes de


employees
Tabela 2.1: Usando ndice sobre surname, firstname, date_of_birth
Colunas especificadas na clusula Where
Surname, firstname, date_of_birth
Surname, firstname
surname, date_of_birth
firstname

Colunas do ndice que podem ser usadas


Surname,firstname,date_of_birth: todas as
colunas no ndice concatenado.
Surname, firstname: As duas colunas so
colunas que conduzem o ndice, ento ambas
podem ser usadas.
Apenas surname. Date_of_birth no pode ser
usada porque ele vem depois de firstname, o
qual no foi especificado.
Nenhuma! O ndice s pode ser usado se a
coluna inicial for especificada.

Diretrizes para criao de ndices Concatenados


As seguintes diretrizes ajudam a decidir quando usar ndice e qual coluna deve ser
usada e em que ordem.
Crie um ndice concatenado para colunas de uma tabela as quais apaream juntas na
clusula WHERE da consulta a ser otimizada.
Se uma coluna as vezes aparecer sozinha na clusula WHERE de outras consultas,
coloque-a no incio do ndice, desta forma o ndice ser usado em mais de uma
consulta.
Quanto mais seletiva for uma coluna mais til ela ser se ficar conduzindo o ndice, ou
seja se estiver no incio do ndice concatenado.
Merge de ndice
Se mais de uma coluna de uma tabela aparecer na clusula where e no existir ndice
concatenado sobre estas colunas mas existir indices sobre as colunas individualmente, ento
Oracle pode decidir por realizar um merge dos indices, para isso ele consulta separadamente
utilizando cada ndice e retorna apenas os dados que esto em ambas as listas. Por exemplo
para consultar um employee com o nome de Ian Smith realizado primeiro uma consulta
por firstname Ian depois todos os employee com surname Smith, realizado um merge das
listas, retornando os employees que esto em ambas as listas.

15

Atravs do plano de execuo da consulta pode-se determinar se o Oracle est fazendo


um merge de indices, mostrado como um AND EQUALS, bom considerar a criao de um
ndice concatenado sobre as colunas usadas pois quase sempre ndice concatenado mais
eficiente que o merge de ndice.
2.2.2 ndices Agrupados
ndice Agrupados so mecanismos para armazenar linhas relacionadas de uma ou mais
tabelas no mesmo segmento. Linhas as quais tem o mesmo valor chave para o agrupamento
so armazenadas juntas. Na teoria isto ir aumentar a velocidade de junes de tabelas, porque
as linhas a serem unidas estaro armazenadas no mesmo bloco. Na prtica, ndices agrupados
so bastante limitados e apenas devem ser usados quando as tabelas so sempre
referenciadas juntas. Abaixo esto algumas das desvantagens de ndices agrupados:
Full table Scan em apenas uma das tabelas do agrupamento ser bastante lento, pois os
blocos para outras tabelas no agrupamento tambm tero que ser escaneados.
Inseres podem ser lentas por causa do esforo adicional de manter o agrupamento.
Os benefcios de performance para as junes podem ser mnimas.
A Figura 2.4 adiante, mostra como um ndice agrupado pode ser implementado para a tabela
PRODUCTS e SALES.
2.2.3 Bitmapped ndices
Bitmapped ndices so a mais nova adio da Oracle estratgia de indexao e foi
introduzido com o Oracle 7.3. Em um ndice bitmap Oracle cria um bitmap para cada valor
nico da coluna em questo. Cada bitmap contm um nico bit (0 ou 1) para cada linha na
tabela. Um 1 indica que a linha tem o valor especificado pelo bitmap e um 0 indica que no
tem. Oracle pode rapidamente escanear estes bitmaps para encontrar linhas que satisfazem um
critrio especfico, tambm pode rapidamente comparar mltiplos bitmaps para encontrar todas
as linhas que satisfazem aos mltiplos critrios. A figura 2.5 mostra um exemplo de ndice
bitmap sobre uma tabela SURVEY. ndices Bitmapped existem sobre gender, marital_status e
own_home. Para encontrar todas as pessoas do sexo masculino que tm casa prpria, Oracle
extrai cada bitmap e seleciona linhas que tem um 1 em cada bitmap.
Comportamento de Index Bitmap
Oferece recuperao rpida para colunas as quais tm apenas poucos valores
distintos e que so freqentemente consultadas juntas. Contudo full table scans
sero mais eficientes se as colunas forem consultadas individualmente.
So especialmente aplicveis para grandes tabelas e para consultas agregadas (ex:
how many)
Podem ser usados em qualquer ordem e em qualquer combinao, assim so mais
flexveis que um ndice concatenado correspondente, o qual requer o uso de pelo
menos a primeira coluna do ndice.
Se usado apropriadamente bastante compacto, bem mais que o ndice
concatenado.
As colunas dele devem ser de baixa cardinalidade, ou seja, as colunas devem ter
poucos valores distintos. Caso contrrio, muitos bitmaps devem ser construdos e
mantidos.
Merge de ndices uma operao bastante eficiente (operaes bit a bit so
bastante rpidas)
16

Problemas de ndice Bitmap


Oracle no capaz de bloquear um nico bit, e consequentemente, bloqueios para
bitmapped ndices so feito para o bloco. Dado que um grande nmero de linhas
(ou bits) podem estar em um nico bloco, muitas linhas sero locadas. Isto torna
ndice bitmap inadequado para aplicaes com um nmero moderado de
transaes.
Ele no adequado para consultas por faixas de valores, ou para colunas com
grande nmero de valores distintos. Se for necessrio deve-se usar B*-Tree index
para estas colunas.
2.2.4 ndices Sobre Tabelas
Anteriormente foi discutido a importncia de se incluir todas as colunas necessrias
para a consulta no ndice concatenado, para se otimizar a performance da consulta. Tambm
uma otimizao significante incluir todas as colunas que aparecem na lista do select no ndice
concatenado a fim de se satisfazer a consulta sem acessar a tabela, utilizando-se apenas o
ndice.
Imagine uma tabela na qual todas as colunas foram includas num ndice concatenado e
para o qual todas as consultas foram satisfeitas usando o ndice. Nesta circunstncia a tabela se
tornou suprflua, pois todos os dados foram armazenados no ndice. Mesmo assim ela
continua a existir e consumir espao de armazenamento e causar overhead quando linhas so
adicionadas, removidas ou alteradas. Neste caso a tabela pode ser descartada e ser mantido
apenas o ndice.
Tabela Product
Para solucionar este
problema
Oracle permite criar uma
tabela organizada como ndice.
Product
IDProduct_descriptionNormal
Value10Fralda
Ela pode ser usada da
mesma
forma
que
outras
tabelas,
mas
internamente
armazenada no
Pampers300020Sabonete Glicerinado200030Etamine 15218000
formato de um B*-Tree ndice. Armazenar uma tabela neste formato se evita a duplicao dos
dados e se assegura que consultas as quais acessam a tabela pela chave primria so
executadas rapidamente, pois apenas um ndex lookup ser necessrio, sem o acesso tabela,
j que a estrutura da tabela organizada pela chave primaria.
Tabela Sales
Product IDCustomerSale_dateOther
Columns...101312/05/200010182/05/2000201207/05/200230
101/01/200230212/12/2002

Indice Agrupado de Sales e Product


Product IDProduct_descriptionNormal Value10Fralda
Pampers3000CustomerSale_dateOther
Columns...1312/05/2000182/05/2000Product
IDProduct_descriptionNormal Value20Sabonete
Glicerinado2000CustomerSale_dateOther
Columns...1207/05/2002Product
IDProduct_descriptionNormal Value30Etamine
15218000CustomerSale_dateOther
Columns...101/01/2002212/12/2002

17

Figura 2.4: Estrutura de um ndice Agrupado

ndice sobre tabelas criado usando a palavra chave ORGANIZATION, na criao da


tabela. No possvel criar um ndice secundrio (ndice sobre uma chave secundria) sobre
uma tabela organizada como ndice, isto porque as linhas de uma tabela organizada como
GenderMarital
ndice no esto
associada a um ROWID ento no tem o que o ndice secundrio apontar.
StatusChildren_ynIncomeOwn_homeMMarriedN$20.000NMSingleN$30.00
0YFDivorcedY$12.000NFMarriedY$70.000YFMarriedY$20.000YMSingle
Tabelas organizadas
como ndice so aplicveis nas seguintes circunstancias:
Y$10.000NFMarriedN$13.000N

Todas as consultas sobre a tabela pode ser satisfeita usando a chave primria.
Nenhum ndice secundrio necessrio.
Uma tabela contm colunas curtas freqentemente acessadas e colunas longas no
freqentemente acessadas
O tamanho total da linha ou das colunas que so freqentemente acessadas
relativamente pequeno.

MaleFemale1010010
1011001

Indice bitmap
sobre Gender

MariedSingleDivorced100010
001100100010100

Indice bitmap sobre Marital Status

YesNo011001
10100101

Indice bitmap
sobre own_home

Select * from survey where Sex=Male and marital_status=Single and own_home=Yes


Male110
0010

Single01
00010
AND

Yes01011
00
AND

0100000
EQUALS

Esta
linha
satisfaz a
consulta
18

Figura 2.5:Exemplo de indice bitmap. Bitmaps para male, single e own_home so usados
para encontrar rapidamente um homem solteiro e com casa prpria na tabela SURVEY.

2.3 Full Table Scan e ndex Lookups


Normalmente existem vrias formas de acesso para uma determinada consulta. Full
Table Scan sempre uma opo e dependendo dos ndices criados sobre a tabela, existem
outras opes de recuperao atravs de ndices.
O otimizador na maioria das vezes escolhe o melhor caminho, mas nem sempre isto
verdade e o desenvolvedor ou DBA deve ser capaz de avaliar a escolha do otimizador e indicar
um melhor caminho, caso seja necessrio.
As duas formas mais comuns de recuperao de dados o Full Table Scan, onde todos
as linhas da tabela so lidas e comparadas com um determinado critrio de seleo, e Index
Lookups onde um ndice usado para se determinar a linha a ser processada.
Normalmente um desenvolvedor tenta evitar um Full Table Scan. Contudo, um Full
Table Scan as vezes consome menos recursos que um acesso equivalente utilizando-se ndice.
Isto ocorre quando o critrio de seleo acessa uma grande proporo dos dados da tabela,
assim uma recuperao por ndice ir necessitar a leitura dos blocos do ndice e da tabela. Alm
do mais Oracle ter que alternar entre blocos de ndice e blocos da tabela, e possivelmente ir
ler um ndice mais de uma vez. Se uma grande poro da tabela for lida, o overhead causado
pela leitura do ndice ser maior que o causado por ler a tabela inteira.
Como vimos anteriormente a percentagem de dados retornados que determinam a
utilizao ou no de ndice no uma regra, varia com a verso do Oracle e com outros
critrios. A melhor forma de decidir analisando a execuo da consulta a ser otimizada e o
impacto do ndice sobre a atualizao, insero e remoo de dados na tabela. Testar a
consulta sobre um volume de dados real um fator decisivo, as seguintes proposies so
indiscutveis:
19

Se a consulta acessar toda a tabela ou uma grande poro da mesma, ento Full
Table Scan a melhor opo.
Se apenas uma linha ser retornada de uma tabela grande (se a tabela contm
poucos dados, uma linha por exemplo, um acesso completo seria melhor!) um
acesso por ndice na coluna da restrio ser o melhor caminho de acesso.
Entre estes dois extremos, pode ser difcil prever qual caminho de acesso ser o
mais rpido, a melhor opo testar as vrias formas de acesso e analisar o
resultado com o SQL_TRACE.
2.4 Evitando Full Table Scan Acidental
Mesmo tendo sido definidas todas as estruturas necessrias para um bom
funcionamento da consulta, a escrita do comando SQL pode fazer com que o otimizador
escolha um caminho errado para execut-la. Consultas envolvendo uma condio != (NOT
EQUAL), que busca por valores NULL ou que utilizam funes que desabilitam o ndice
podem provocar um acesso errado a tabela.
Usando NOT EQUALS ( != )
Oracle no utilizar ndice quando a condio da consulta utiliza o operador != . Isto
geralmente acontece porque quando se vai retornar linhas, exceto aquelas que combinam com
um nico valor, um full table scan parece ser o meio mais rpido de retornar os dados.
Contudo se o valor em questo representa uma grande percentagem da tabela esta no ser a
melhor opo. Se certo que a consulta ir se beneficiar de uma abordagem baseada em
ndice, uma soluo rescrever a consulta usando IN, OR ou >, e se for necessrio encorajar o
Oracle a utilizar o ndice apropriado usando hints.
Como exemplo suponha os seguintes valores para a coluna CUSTOMER_STATUS da
tabela CUSTOMERS: VALID, OVERDUE ou CANCELED. Suponha tambm que a
grande maioria dos valores (mais que 95%) so VALID. Para consultar todos os customers
que no so VALID, a seguinte consulta pode ser escrita:
Select customer_id from customers where customer_status != VALID
Analisando o plano de execuo da mesma v-se que um acesso FULL foi realizado.
Select customer_id from customers where customer_status IN (CANCELED, OVERDUE)
Mesmo reescrevendo a consulta o otimizador continua utilizando um acesso FULL. Pois ele
calcula que dois teros da tabela sero retornados, j que s tem trs valores distintos.
Select /*+ INDEX(CUSTOMER CUSTOMER_STATUS_IDX*/
customer_id from customers where customer_status IN (CANCELED, OVERDUE)
Utilizando-se o hint (entre /* e */) acima consegue-se a utilizao do ndice, o mesmo
resultado seria obtido sem o uso do hint se um histograma da tabela tivesse sido gerado, pois o
otimizador saberia qual a real proporo dos dados na tabela, mas esta operao tem um custo
adicional e arriscado esperar que o histograma esteja sempre atualizado.
Consultando valores NULL
Quando uma coluna indexada NULL, ou todas as colunas de um ndice concatenado,
ento a linha correspondente no ter entrada no ndice [1]. Ou seja, nulls no so indexados.
Este conceito de fundamental importncia pois no possvel usar um ndice para encontrar
20

valores NULL, atravs dele s possvel encontrar um valor NOT NULL. Quando se utiliza a
condio IS NULL na clausula WHERE de uma consulta necessrio considerar o impacto
desta escolha sobre a performance da mesma, pois o acesso ser feito atravs de um full table
scan, j que no pode-se utilizar ndice para procurar valores NULL.
Como exemplo, vamos supor que a coluna CUSTOMER_STATUS pode conter valores
NULL, a seguinte consulta encontra estes customers:
Select customer_name from customer where status is null
Uma consulta como esta sempre utilizar um acesso full, este problema pode ser
resolvido se a coluna indexada for definida como NOT NULL e um valor default for dados aos
status que eram NULL, por exemplo UNKNOWN, assim pode-se utilizar um hint para que o
otimizador utilize o ndice, como mostra a consulta abaixo, ou definir um histograma para a
tabela.
Select /*+INDEX(CUSTOMERS CUSTOMER_STATUS_INDEX)*/ from customer
where status= UNKNOWN
Usando funes sobre colunas de ndice
Aplicando uma funo a uma coluna indexada impossibilita que o ndice seja usado.
No passado isto era usado como meio de influenciar o otimizador baseado em regra para que
ele no usasse determinado ndice, hoje hints fornecem um meio bem mais poderoso e bem
documentado. Obviamente isto pode acontecer no intencionalmente, e se isto ocorrer pode
ser bastante difcil localizar o problema pois no mostrado no plano de execuo da consulta
porque determinado caminho de acesso est sendo seguido, apenas o caminho mostrado.
uma boa prtica tentar aplicar funes recprocas aos valores buscados sem aplicar a coluna.
Por exemplo, a seguinte consulta retorna os detalhes de um customer, onde os parmetros :1
e :2 foram informados por um usurio a partir de uma tela qualquer do sistema:
Select customer_id,customer_name from customer where contact_surname = :1
And contact_firstname = :2
Para assegurar que letras maiscula e minscula no influenciem no resultado da consulta o
SQL pode ser alterado para o seguinte:
Select customer_id,customer_name from customer where
Upper(contact_surname) = upper( :1 )
And upper( contact_firstname )= upper( :2 )
A funo upper usada resolve o problema, mas desabilita o uso do ndice. Sempre que possvel
pode-se aplicar uma funo recproca ao valor sendo buscado. Por exemplo se os dados na
tabela fossem sempre guardados com letras maisculas a funo upper s necessitaria ser
aplicada ao valor sendo procurado e no a coluna, possibilitando assim o uso do ndice.
Um outro uso de funes que tambm impede o uso de ndice e que mais difcil ainda
de encontrar quando se compara valores de tipos diferentes, pois internamente algumas
verses do Oracle usa funes de converso de tipos para poder realizar a consulta, e esta
converso no informada ao usurio. Por exemplo, se uma coluna numrica est sendo
comparada a um caracter, antes da comparao ser feita uma converso de tipos. Por
exemplo, coluna_numerica=1 ser transformado internamente para to_char(coluna_numerica)
= 1.
Usando o Operador LIKE
21

O operador like pode ser usado para procurar por linhas em que determinada coluna
combina com um wildcard (um exemplo de wildcard seria HARD%). Por exemplo a consulta
seguinte seleciona todos os curstomers com surname iniciando com HARD.
Select count(*) from customers where contact_surname like HARD%.
Esta consulta faz um bom uso do ndice sobre surname e requer poucos recursos de I/O
para ser satisfeita. Contudo, se utilizarmos um wildcard para o final do surname o ndice no
poder ser usado diretamente. Por exemplo, se desejarmos encontrar todos os customers cujo
surname termina com RDY, usando a seguinte consulta:
Select count(*) from customers where contact_surname like %RDY.
A consulta acima ser resolvida com um Full Table Scan, isto porque o otimizador no
pode encontrar o ndice apropriado a menos que os caracteres iniciais sejam informados. Mas
ainda pode-se tirar proveito do ndice se utilizarmos hints para forar o otimizador a utilizar o
ndice. Desta forma ser realizado um full table scan no ndice o que consome menos tempo
que na tabela pois o ndice armazena menos dados a serem scaneados. Fisicamente ele contm
apenas o surname e o ROWID, enquanto a tabela contm todas as colunas. Assim necessrio
menos recursos de I/O para ler o ndice inteiro do que para ler a tabela inteira.
Para forar a utilizao do ndice a seguinte consulta pode ser utilizada:
Select /*+ INDEX(CUSTOMERS SURNAME_ONLY )*/ count(*) from customers
where contact_surname like %RDY.
A Figura 2.4 abaixo mostra os benefcios conseguidos com as melhorias citadas acima.

like 'HAR%' - full table scan


like '%RDY' usando Full Table SCAN
like '%RDY' - usando index
like 'HAR%' usando index
0

200

400

600

800

1000

1200

Blocos lidos

Figura 2.4: Usando ndice com o operador like


3. Otimizando Junes e Subconsultas
Neste tpico sero discutidas formas de melhoria de performance quando duas ou mais
tabelas so unidas. A maioria dos comandos SQL no triviais contm junes, e assegurar que
as tabelas envolvidas so juntas da melhor maneira possvel tambm objetivo da otimizao
de consultas.
O otimizador Oracle far seu melhor para assegurar que o tipo do juno e a ordem em
que as tabelas so unidas a melhor possvel. As vezes o otimizador ser incapaz de
22

determinar o melhor plano para a juno por causa de limitaes nos seus algoritmos e do seu
entendimento dos dados. Cabe ento a quem escreveu a consulta forar a melhor abordagem
para a juno atravs de hints ou outras formas.
Subconsultas so bastante parecidas com junes, elas permitem que uma consulta
SQL seja embutida em um outro comando SQL e pode freqentemente realizar operaes
similares s junes possivelmente mais eficiente. Subconsultas podem tambm ser usadas
para expressar o inverso de uma juno pela retirada de linhas de uma tabela que no
combinam com um critrio especfico em outra tabela.
Subconsultas podem ser usadas para formular consultas bastante complexas, e quanto
mais complexa for a consulta mais fcil ser de o otimizador errar o caminho escolhido. Aqui
ser discutido quando usar subconsultas, que tipo de subconsulta usar e formas de melhorar a
performance das mesmas.
3.1. Tipos de Juno
Junes permitem que linhas de uma ou mais tabelas sejam fundidas baseando-se em
um valor chave comum. A maioria dos comandos SQL no triviais envolvem junes. Oracle
suporta trs tcnicas de juno:
Sort Merge Join um mtodo de unir tabelas sem que seja necessrio o uso de
indices. Oracle ordena cada tabela, ou o resultado de uma operao prvia,
utilizando a coluna usada para a juno como parmetro de ordenao, ento ele
fundi os dois resultados ordenados em outro tambm ordenado. como se tivesse
duas pilhas de pginas numeradas, por exemplo pginas pares em uma pilha e
pginas impares na outra pilha em alguma ordem randmica. Para unir estas duas
pilhas em uma, na ordem correta, deve-se ordenar cada pilha e ento intercal-las.
Nested Loops join um algoritmo de juno o qual normalmente envolve um
ndice em pelo menos uma das tabelas. Em um nested loop join, um full table scan
feito sobre uma das tabelas ou result set, provavelmente a menor tabela ou a
tabela que no tem ndice na coluna da juno. Para toda linha encontrada no result
set, uma busca normalmente envolvendo um ndice realizada sobre a segunda
tabela e a linha que combina com ela retornada.
Hash join neste tipo de juno, uma tabela hash construda para a maior das duas
tabelas. A menor tabela ento scaneada e a hash table usada para encontrar as
linhas que combinam com a tabela maior. Este tipo de juno funciona muito bem,
especialmente se a hash table pode permanecer na memria (caso contrrio, tabelas
temporrias tm de ser alocadas). Este tipo de juno bastante aplicado se as duas
tabelas so de tamanhos diferentes, com anti-joins e com SQL paralelo.
3.2. Escolhendo o melhor mtodo de juno
Em certo sentido, sort merge join e hash join podem ser considerados como da mesma
famlia de juno eles fornecem boa performance sobre condies semelhantes. Por outro
lado, o nested loop join de uma categoria de consultas bastante diferente. Ento, antes de
decidir qual tipo de juno utilizar deve-se decidir se um nested loop join apropriado.
A deciso entre sort merge/hash join ou nested loop join deve se basear sobre:

23

A necessidade por throughput verso a necessidade por tempo de resposta. Nested


loops normalmente oferecem melhor tempo de resposta mas sort merge pode
oferecer melhor throughput.
A proporo da tabela que est sendo unida. Quanto maior o subconjunto de linhas
que est sendo processado, mais provavelmente um sort merge ou hash ser mais
rpido.
ndices disponveis para suportar a juno. Nested loop normalmente s vale a pena
quando um ndice pode ser usado para unir as tabelas.
Memria e CPU disponveis para ordenao. Ordenao de grandes quantidades de
dados consome muitos recursos e torna a execuo lenta. Sort merge realiza duas
ordenaes, enquanto nested loops normalmente no envolve ordenao. Hash
joins tambm requer memria para construir a hash table.
Sort merge e hash joins podem ter grandes benefcio da execuo paralela
embora nested loop joins tambm possa ser paralelizado.
A tabela 3.1 fornece diretrizes gerais para decidir entre duas tcnicas de juno[1].
Para casos que no se adeqem, deve-se testar os dois mtodos e usar uma ferramenta para
determinar qual mtodo tem melhor performance. Por exemplo, o SQL_TRACE para traar
o plano de execuo e para conferir o tempo de resposta da consulta.
Tabela 3.1: Decidindo entre sort merge e nested loops joins.
Quando unir A a B (nesta Consiredar sort merge ou Considerar nested loops
ordem)
hash join?
usando um ndice sobre B?
A e B so pequenas
Sim
Talvez depende do quanto
pequenas as tabelas so
selecionado apenas um
No realizar um table scan Sim o ndice ir reduzir o
pequeno subconjunto de linhas de B ter um custo ineficiente nmero de I/Os em B
de B.
Se quer a primeira linha to No a primeira linha no Sim linhas podem ser
rpido quanto possvel
ser retornada at que A e B retornadas to rpido quanto
tenham sido percorridas, elas possam ser buscadas
ordenadas e juntas ou at que usando o ndice
a hash table tenha sido
construda.
Se quer todas as linhas to Talvez
Talvez nested loops pode ter
rpido quanto possvel
retornado todas as linhas antes
do sort merge se outras
condies se aplicam
Fazendo um full table scan de Sim
Sim nested loops podem ser
A e usando consulta paralela
resolvidos em paralelo
Pegando linha de A utilizando Sim sort merge e hash joins No nested loops no
uma busca com ndice e podem ser feitos em paralelo, podem ser resolvidos em
usando consulta paralela.
mesmo se um result set foi paralelo a menos que a
retornado por um ndice primeira tabela da juno, a
lookup
tabela de fora, foi recuperada
via um full table scan
A memria limitada e a rea Talvez no uma grande Sim nested loop joins evitam
disponvel para ordenao ordenao tem um overhead ordenao por isso so menos
pequena
significante, especialmente se afetados por limitao de
a memria para a ordenao memria.
24

limitada. Um hash join mais


indicado que um sort merge.
Exemplos de Nested Loops e Sort Merge e Hash Joins
Para forar o otimizador a usar um Nested Loop Join pode-se usar o hint USE_NL.
Lembrando que a tabela especificada no hint a tabela interna da juno: a segunda tabela na
ordem da juno. No caso do nested loop ela normalmente a tabela que contm o ndice para
suportar a juno. A consulta abaixo ser analisada para os trs tipos de juno. O hint
ORDERED foi usado para assegurar a ordem correta da juno.
Usando Nested Loop join
select /*+ ORDERED USE_NL(E) */
count(*)
from customers c,
employees e
where c.sales_rep_id = e.employee_id
Rows
Execution Plan
--------- ----------------------------------------0 SELECT STATEMENT GOAL: CHOOSE
0 SORT (AGGREGATE) ordenao para o count(*)
99500
NESTED LOOPS
TABLE ACCESS GOAL: ANALYZED (FULL) OF CUSTOMERS
100000
100000
INDEX GOAL: ANALYZED (UNIQUE SCAN) OF PK_EMPLOYEES
(UNIQUE) Juno feita com o ndice em vez da tabela
Usando Sort Merge join
select /*+ ORDERED USE_MERGE(E) */
count(*)
from customers c,
employees e
where c.sales_rep_id = e.employee_id

Rows
Execution Plan
--------- ----------------------------------------0
SELECT STATEMENT GOAL: CHOOSE
0
SORT (AGGREGATE) ordenao para o count(*)
99500
MERGE JOIN
100000
SORT (JOIN) ordenao feita para join
100000
TABLE ACCESS GOAL: ANALYZED (FULL) OF CUSTOMERS
800
SORT (JOIN) ordenao feita para join
800
TABLE ACCESS GOAL: ANALYZED (FULL) OF EMPLOYEES
25

Este plano de execuo mostra que esta uma escolha pior que a anterior pois as duas tabelas
foram ordenadas e feito um acesso completo a elas.
Usando Hash Join
Se as condies favorecem um sorte merge sobre um nested looop join, possvel que
usando um hash join uma performance maior seja alcanada. Na maioria das circunstncias um
hash join equivalente ao sort merge join e deve ter performance maior para grandes tabelas
quando uma das tabelas muito maior que a outra. O otimizador baseado em custo ir optar
pelo hash join automaticamente se avaliar que esta a melhor opo. Caso se ache que este
no o melhor caminho, pode-se desabilitar o parmetro HASH_JOIN_ENABLED=FALSE
para assegurar que ele no seja usado. Abaixo est a consulta e o plano de execuo
utilizando-se o hash join.
select /*+ ORDERED USE_HASH(E) */
count(*)
from customers c,
employees e
where c.sales_rep_id = e.employee_id
Rows
Execution Plan
--------- ----------------------------------------0
SELECT STATEMENT GOAL: CHOOSE
0
SORT (AGGREGATE) ordenao para o count(*)
100000
HASH JOIN
100000
TABLE ACCESS GOAL: ANALYZED (FULL) OF CUSTOMERS
800
TABLE ACCESS GOAL: ANALYZED (FULL) OF EMPLOYEES
A partir do plano de execuo, vemos que esta juno no utiliza ordenao. Assim, se a tabela
muito grande para ser ordenada, mas no to grande para a hash table permanecer na
memria, ento os ganhos na performance sero dramticos.
Comparao da performance das junes
O grfico da Figura 3.1 mostra o tempo de execuo da consulta analisada
anteriormente com os trs tipos de juno.

Nested Loops
Sort Merge
Hash Join
0

10

15

20

25

Tempo de Execuo(s)

Figura 3.1: Comparao das tcnicas de join consultando todas as linhas em


CUSTOMERS e EMPLOYEES.
26

A partir do grfico da Figura 3.1 v-se que nested loop a pior escolha, isto ocorre
porque a juno acessa todas as linhas das duas tabelas, sort merge join ter uma performance
melhor e hash join melhor ainda. No se deve usar nested loop join quando juntando todas ou
a maioria das linhas de uma tabela, mas ele ser bem aplicado quando um pequeno subconjunto
da tabela estiver sendo processado. Por exemplo, a consulta abaixo retorna dados apenas para
clientes cujo representante das vendas Colin James:
select /*+ ORDERED USE_NL(C) */
c.customer_name
from employees e,
customers c
where c.sales_rep_id = e.employee_id
and e.surname = JAMES
and e.firstname = COLIN
O grfico da Figura 3.2 mostra o resultado obtido utilizando-se a consulta acima com
os trs mtodos de juno. O Nested loop join o melhor dos trs, pois existe um ndice
apropriado para suportar a juno. Sort merge e hash joins so menos eficientes, contudo
hash join ainda bastante superior ao sort merge join.
3.3. Escolhendo a melhor ordem das tabelas para a juno
Determinar a melhor ordem possvel para a juno pode ser complexo. Dependendo do
nmero de tabelas envolvidas teremos inmeros mtodos de acesso e ordens para a juno. O
nmero de possibilidades ser da ordem do fatorial do nmero de tabelas envolvidas na
clusula FROM. Por exemplo, se existem cinco tabelas na clusula FROM, ento o nmero de
possibilidades para a ordem da juno ser:
5! = 5*4*3*2*1 = 120
O otimizador baseado em custo tentar encontrar a melhor soluo se baseando no
custo de algumas possibilidades de acesso e ordem da juno, para isso ele tomar algumas
suposies, por exemplo, o custo de uma ordenao baseado no tamanho da tabela, o nmero
de linhas a ser recuperado por um ndex lookup, e assim por diante. O otimizador baseado em
regra usar um conjunto de regras para achar a melhor abordagem. Ambos os otimizadores
cometem enganos na escolha da melhor soluo. O mais seguro ser tentar vrias abordagens
para a juno.

Sort Merge
Hash Join
Nested Loops
0

10

12

14

16

Tempo de Execuo(s)

Figura 3.2: Comparao das tcnicas de join consultando pequeno subconjunto


de EMPLOYEES. relacionados com CUSTOMERS.

27

No possvel prever qual ser a melhor abordagem para todas as consultas, mas
algumas dicas ajudam na escolha, e podem ser usadas como uma primeira tentativa:

A driving table a primeira tabela na ordem da juno - dever ser aquela que
retorna o menor nmero de linhas, ou seja, ela dever ser a menor tabela, ou se
existir uma condio WHERE sobre a tabela, esta dever retornar o menor nmero
de linhas. Isto possibilita que as tabelas subseqentes possam ser unidas
eficientemente.
A menos que se espere acessar uma grande quantidade da tabela, tente usar nested
loop join para cada juno subseqente. Se a juno est acessando uma grande
poro da tabela tente sort merge ou hash join.
Tenha certeza de que o ndice que suporta o nested loop join formado por todas
as colunas envolvidas na clusula where para a tabela sendo unida.

3.4. Outer Join


Outer join um tipo de juno onde se permite incluir linhas da outer table (tabela
secundria da juno) que no combina com nehuma linha na inner table. Por exemplo,
quando retornando o departamento de todos os empregados pode-se retornar tambm os que
no tem departamento.
A performance do outer join, normalmente similar a do inner join correspondente, e
todas as formas de juno esto disponveis. Contudo um outer join impe uma ordem
particular a juno. Se realizarmos uma juno de A para B retornando linhas de B mesmo que
no combinem com nehuma em A, ento a ordem da juno dever ser A, B no podendo ser
B,A. Isto impossibilita que determinado tipo de juno possa ser usada, degradando a
performance da consulta.
Por exemplo, a consulta abaixo, que une departamentos a empregados:
Select /*+ RULE*/ d.department_name, e.surname
From departments d, employees e
Where d.department_id = e.department_id
Execution Plan
NESTED LOOPS
TABLE ACCESS FULL EMPLOYEES
TABLE ACCESS BY ROWID DEPARTMENTS
INDEX UNIQUE SCAN PK_DEPARTMENTS
Como existe um ndice em department, usado Nested Loop e a ordem da juno D,
E. Se esta consulta for transformada em um outer join, como mostra abaixo, teremos o
seguinte resultado:
Select /*+ RULE*/ d.department_name, e.surname
From departments d, employees e
Where d.department_id = e.department_id (+)

28

Execution Plan
MERGE JOIN OUTER
SORT JOIN
TABLE ACCESS FULL DEPARTMENTS
SORT JOIN
TABLE ACCESS FULL EMPLOYEES
Como resultado do outer join no apenas a ordem da juno mudou, mas tambm o
tipo da juno. Pode-se usar um nested loop join quando employees so unidos a departments
porque existe um ndice sobre department_id na tabela departments. Quando muda-se para o
outer join, a ordem das tabelas inverte e no tem ndice em employees na coluna
department_id para suportar a juno, ento a nica opo usar um sort merge join.
importante verificar que outer join limita a ordem da juno a qual o otimizador
poder considerar, por isso no deve-se utilizar outer join desnecessariamente.
3.5. Consulta Hierrquica
Uma consulta hierrquica um tipo especial de self join. Na consulta hierrquica, uma
coluna da tabela aponta para outra linha da mesma tabela, esta linha aponta para outra e assim
por diante, at o topo da hierarquia ser encontrado. Este tipo de dado muito usado para
representar estruturas em rvore. Oracle realiza consultas hierrquicas atravs do operador
CONNECT BY, que usado junto com START WITH. No banco de dados de exemplo, cujo
modelo est no captulo 1, as colunas manager_id e employee_id da tabela employees formam
esta hierarquia. A coluna manager_id aponta para employee_id. Por exemplo, se queremos
construir a hierarquia completa dos employees podemos usar a seguinte consulta:
Select rpad( , level*3) || surname employee
From employees
Start with manager_id=0
Connect by prior employee_id = manager_id
Para que uma consulta hierrquica em uma grande tabela seja eficiente, precisa-se de
um ndice para suportar as clusulas start with e connect by. No caso da consulta acima, isto
significa um ndice em manager_id. O ndice em manager_id requerido para posicionar
inicialmente em manager_id=0 e para encontrar employees com um manager_id particular.
Sem o ndice temos o seguinte plano de execuo para a consulta:
Rows
Execution Plan
--------- ----------------------------------------0
SELECT STATEMENT HINT: CHOOSE
800
CONNECT BY
800
TABLE ACCESS HINT: ANALYZED (FULL) OF EMPLOYEES
1
TABLE ACCESS HINT: ANALYZED (BY ROWID) OF EMPLOYEES
640000
TABLE ACCESS HINT: ANALYZED (FULL) OF EMPLOYEES
Note as 640 000 linhas processadas no segundo full table scan em employees.
Employees uma tabela de 800 linhas, mas na consulta necessrio para cada linha em
employees, realizar outra busca para encontrar os manager_ids correspondentes, o que faz
com que sejam processadas 800 X 800 = 640 000 linhas, um clssico problema de
performance.
29

Criando um ndice em manager_id a mesma consulta ter um plano de execuo bem


mais agradvel:
Rows
Execution Plan
--------- ----------------------------------------0
SELECT STATEMENT HINT: CHOOSE
800
CONNECT BY
2
INDEX (RANGE SCAN) OF EMPLOYEES_MANAGER_IDX
1
TABLE ACCESS HINT: ANALYZED (BY ROWID) OF EMPLOYEES
799
TABLE ACCESS HINT: ANALYZED (BY ROWID) OF EMPLOYEES
1599
INDEX (RANGE SCAN) OF EMPLOYEES_MANAGER_IDX
Quando uma consulta hierrquica realizada usando-se o operador CONNECT BY
deve-se assegurar que as clausulas START WITH e CONNECT BY sejam resolvidas usandose ndice. A Figura 3.3 mostra o ganho obtido com o uso do ndice.

Consulta Hierarquica Sem ndex


Consulta Hierrquica com ndex
0

5.000 10.000 15.000 20.000 25.000 30.000 35.000 40.000


Blocos recebidos

Figura 3.3: Melhoria da performance obtida pela criao de ndice para suportar a consulta hierrquica

Quando se quer recuperar um subconjunto de uma hierarquia, por exemplo imprimir a


hierarquia de empregados para um departamento especfico, pode-se adicionar uma condio
WHERE:
Select rpad( , level*3) || surname emloyee
From employees
Where department_id = (select department_id from departments where
department_name = Compiler products)
Start with manager_id=0
Connect by prior employee_id = manager_id
Infelizmente, quando se usa a clusula WHERE Oracle constri a hierarquia antes de
eliminar linhas usando a condio do WHERE. Ou seja as clusulas START WITH e
CONNECT BY so processadas antes da clusula WHERE.
Pode-se ter o mesmo resultado da consulta anterior com um custo mais reduzido
mudando a clausula START WITH :
Select rpad( , level*3) || surname emloyee
30

From employees
Start with manager_id = (select manager_id from departments where
department_name = Compiler products)
Connect by prior employee_id = manager_id
O grfico da Figura 3.4 mostra as melhorias obtidas com esta alterao. Este resultado
s alcanado porque, utilizando-se a condio no START WITH se evita uma montagem
desnecessria da hierarquia.

Eliminando linhas usando


a clausula WHERE
Eliminando linhas usando
a clausula S TART WITH

500

1.000

1.500

2.000

2.500

3.000

3.500

Blocos Lidos

Figura 3.4: Melhoria da performance obtida pela criao de ndice para suportar a consulta hierrquica

Consultas hierrquicas tm certas limitaes, as quais podem afetar a performance de


consultas complexas envolvendo uma consulta deste tipo.
Um SELECT que tenha uma consulta hierrquica no pode incluir uma juno, nem
pode incluir uma subconsulta. Como resultado, se tentamos incluir uma consulta hierrquica
dentro de uma consulta mais complexa, as opes de melhoria da consulta sero bastante
limitadas. Deve-se portanto evitar colocar consulta hierrquica dentro de subconsultas e
lembrar que elas no podem incluir subconsultas ou juno.
3.6. Subconsulta Simples
Uma subconsulta um comando select contido em outro comando SQL. O outro
comando, as vezes chamado de comando de fora ou pai, pode ser outro comando SELECT,
um comando DML (DELET, INSERT OU UPDATE), ou um comando DDL (por exemplo
CREAT TABLE).
Uma subconsulta simples uma consulta que no faz referncia consulta pai. No caso
de uma subconsulta simples tanto a consulta pai quanto a filha so completas e podem ser
executadas sozinhas e independentemente.
Por exemplo, a consulta abaixo retorna o nmero de empregados que tm o menor
salrio da firma:
Select count(*)
From employees
Where salary = (select min(salary) from employees)
31

Substituindo a consulta interna pelo menor salrio da firma, ambas as consultas podem
ser executadas independentemente, ento elas tambm podem ser otimizadas separadamente.
Assim, uma subconsultas simples est otimizada quando as consultas envolvidas esto
otimizadas por si s.
3.7. Subconsultas envolvendo o operador IN
Subconsultas que envolvem o operador IN so bastante comuns. Elas permitem que um
result set seja retornado de uma consulta filha para a consulta pai . Como exemplo a consulta
abaixo retorna a contagem dos customers que parecem ser employees:
Select count(*)
From customers
Where (contact_surname, contact_firstname,date_of_birth) in
(select surname, first_name, date_of_birth from employees)
A maioria das consultas usando a clausula IN pode ser reformulada como uma juno,
por exemplo, a consulta abaixo ir retornar o mesmo resultado que a do exemplo anterior:
Select count(*)
From customers c, employees e
Where c.contact_surname = e. surname
and c.contact_firstname = e.first_name
and c.date_of_birth = e. date_of_birth
Oracle as vezes transforma automaticamente uma subconsultas contendo IN em seu
correspondente utilizando juno, principalmente se as colunas da juno correspondem a uma
chave nica ou a uma chave primria.
Se uma subconsulta contendo IN no for transformada para uma juno, Oracle ir
executar a subconsulta e criar uma tabela temporria baseada nela. Esta tabela temporria ser
ento unida consulta pai provavelmente usando um sort merge join pois a tabela
temporria no tem ndices. Se a mesma consulta for recodificada, ou se o Oracle transformla em uma juno, ento ser possvel utilizar algum ndice existente na tabela referenciada na
subconsulta. Utilizando-se juno tambm tira-se vantagem dos algoritmos de hash join, que
so mais eficientes que os de sort merge join.
Uma vez que o otimizador pode fazer uso de ndices e de facilidades do hash join, uma
consulta utilizando juno freqentemente mais eficiente que sua subconsulta equivalente
utilizando IN, caso ela exista. O grfico da figura 3.5 ilustra a superioridade do nested loop e
hash join sobre a subconsulta equivalente usando IN.
3.8. Subconsultas Correlacionadas
Uma subconsulta correlacionada uma em que a consulta filha executada uma vez
para cada linha retornada pela consulta pai. Por exemplo, a consulta a seguir encontra
empregados com o maior salrio para cada departamento. Para fazer isto, ela executa a
subconsulta
toda linha na
S ubconsulta(a
comqual
IN encontra o maior salrio para um departamento) para99.957
consulta pai:
100.151

S ort Merge Join

Nested Loops Join

3.234

Hash Join

2.523
0

20.000

40.000

60.000

80.000

100.000

Blocos Lidos

Figura 3.5: Subconsulta usando IN comparada com outras alternativas equivalentes de juno

120.000

32

Select department_id, employee_id, surname, firstname


From employee e1
Where salary= (
Select max(salary)
From employees
Where department_id = e1.department_id )
J que a subconsulta ser executada muitas vezes essencial que ela execute
eficientemente. Quase sempre isto significa criar um ndice apropriado para suportar a
subconsulta. Com o ndice default da tabela EMPLOYEES, ns temos o seguinte plano de
execuo:
Rows
Execution Plan
--------- ----------------------------------------0
SELECT STATEMENT HINT: CHOOSE
800
FILTER
800
TABLE ACCESS (FULL) OF EMPLOYEES
97789
SORT (AGGREGATE)
497600
TABLE ACCESS (FULL) OF EMPLOYEES
Pode-se ver que o plano de execuo bastante caro. So processadas cerca de
500000 linhas da tabela EMPLOYEES, enquanto a tabela contm apenas 800 linhas. O grande
nmero de linhas processadas se deve ao fato de a subconsulta est sendo processada 800
vezes, sendo realizado um full table scan em cada vez.
Claramente essencial que o full table scan seja evitado na subconsulta. Se for criado
um ndice sobre department_id, temos o seguinte plano de execuo:
Rows
Execution Plan
--------- ----------------------------------------0
SELECT STATEMENT HINT: CHOOSE
800
FILTER
800
TABLE ACCESS (FULL) OF EMPLOYEES
97789
SORT (AGGREGATE)
97789
TABLE ACCESS (BY ROWID) OF EMPLOYEES
98410
INDEX (RANGE SCAN) OF DEPARTMENT_IDX (NON-UNIQUE)
O ndice usado para recuperar empregados de um departamento especfico, mas
continua-se tendo que acessar a tabela para recuperar o salrio mximo. Como resultado esta
33

a pior escolha. Se o ndice for criado sobre department_id e salary, teremos o seguinte plano de
execuo:
Rows
Execution Plan
--------- ----------------------------------------0
SELECT STATEMENT HINT: CHOOSE
800
FILTER
800
TABLE ACCESS (FULL) OF EMPLOYEES
97789
SORT (AGGREGATE)
98410
INDEX (RANGE SCAN) OF DEPARTMENT_SAL_IDX
Agora a subconsulta pode ser satisfeita apenas pelo ndice. A Figura 3.6 mostra as
melhorias obtidas.
3.9. Subconsulta Correlacionada usando EXISTS
EXISTS um operador especial usado apenas em subconsultas e quase sempre em
subconsultas correlacionadas. O operador EXISTS retorna TRUE se a subconsulta retorna
uma ou mais linhas e FALSE caso contrrio. Por exemplo, a consulta seguinte usa o operador
EXISTS para retornar detalhes de departamentos com empregados:
Select * from departments where exists
(select * from employees where department_id = departments.department_id)

ndex em deparment_id

197.664

30.704

Nenhum ndex
Index em
department_id,salary

3.138
0

40.000

80.000

120.000

160.000

200.000

Blocos Lidos

igura 3.6: Subconsulta usando IN comparada com outras alternativas equivalentes de join

Os princpios para otimizar um comando SQL contendo uma subconsulta com


EXISTS so fundamentalmente os mesmos que para qualquer subconsulta correlacionada.
Como nos exemplos anteriores, esta otimizao envolve a criao de um ndice apropriado
sobre as colunas referenciadas na subconsulta. Para a consulta anterior, sem um ndice sobre
EMPLOYEES.DEPARTMENT_ID temos o seguinte plano de execuo:
34

Rows
Execution Plan
--------- ----------------------------------------0
SELECT STATEMENT HINT: CHOOSE
51
FILTER
51
TABLE ACCESS (FULL) OF DEPARTMENTS
15700
TABLE ACCESS (FULL) OF EMPLOYEES
Se um ndice em employees.department_id for criado, o plano de execuo ser:
Rows
Execution Plan
--------- ----------------------------------------0
SELECT STATEMENT HINT: CHOOSE
51
FILTER
51
TABLE ACCESS (FULL) OF DEPARTMENTS
51
INDEX (RANGE SCAN) OF EMPLOYEE_DEPT_IDX) (NON-UNIQUE)
Quando usar EXISTS
As vezes usar o operador EXISTS a nica forma de expressar uma consulta
complexa. Contudo, grande parte das consultas usando EXISTS pode ser reformulada tambm
usando IN ou juno. Por exemplo, as duas consultas abaixo so equivalentes ao exemplo
anterior usando EXISTS:

Select * from departments where department_id in


(select distinct department_id from employees)
select distinct d.*
from departments d, employees e
where d.department_id = e.department_id
Quando decidindo entre uma subconsulta com EXISTS ou uma subconsulta com IN,
deve-se considerar algumas diferenas fundamentais entre as duas abordagens:
Uma subconsulta com IN executada uma vez, enquanto uma subconsulta com
EXISTS executada uma vez para cada linha da consulta pai.
Uma subconsulta com IN pode no ser capaz de tomar vantagem de ndice
sobre a tabela da subconsulta, enquanto EXISTS pode.
Uma subconsulta com EXISTS no pode tomar vantagem de ndice na consulta
pai, enquanto IN pode.
O otimizador as vezes traduzir automaticamente subconsultas baseadas em IN
em junes.
Tabela 3.2: Decidindo entre subconsultas com IN ou EXISTS [1]
Situao
Usar EXISTS?
Existe um ndice para suportar SIM
SIM

Usar IN?
35

a execuo da subconsulta
No existe ndice disponvel No. Cada execuo da Sim.
A subconsulta

para suportar a subconsulta


subconsulta ir requerer um executada apenas uma vez,
scan na tabela
ento um scan pode ser
aceitvel
A subconsulta retorna um Possivelmente no. EXISTS Sim.
A subconsulta

grande nmero de linhas


ir recuperar estas linhas uma executada apenas uma vez,
vez para cada linha na ento recuperar um grande
consulta pai.
nmero de linhas pode ser
aceitvel.
A subconsulta retorna uma ou Sim, quanto menos for o Sim, se indicado por outros
poucas linhas
subconjunto
retornado
e fatores.
menor for o overhead, mais
aplicvel EXISTS ser.
A maiora das linhas pai so Possivelmente no. Como Sim., como a subconsulta
eliminadas pela subconsulta
EXISTS ser executado para executada apenas uma vez, as
cada linha na consulta pai, o linhas pai sero eliminadas
overhead ser alto se apenas eficientemente.
uma minoria das linhas so
eventualmente retornadas.
Existe um ndice nas colunas Possivelmente no. EXISTS Sim. A subconsulta com IN
pai, o qual combina com as no ser capaz de tomar pode usar o ndice.
colunas na subconsulta
vantagem do ndice
A consulta anterior um bom candidato para usar EXISTS. O full table scan de
DEPARTMENTS aceitvel e inevitvel, e a busca por department_id em employees
suportada pelo ndice employee_dept_idx. A formulao da consulta com EXISTS possui
melhor performance que a soluo usando IN e a soluo usando juno, como mostra a
Figura 3.7. Contudo, muitas consultas que trabalham muito bem com o operador IN sofrero
drstica degradao de performance se re-codificado com EXISTS, ento use EXISTS com
cuidado.

0,23

Join

0,03

S ubquery com IN

0,01

S ubquery com EXIS TS

0,05

0,1

0,15

0,2

0,25

0,3

Tempo transcorrido (s)

Figura 3.7: Performance de subconsulta com EXISTS versos subconsultas equivalentes usando IN e
usando join.

Anti-Join

36

Anti join um tipo de juno o qual retorna linhas de uma tabela que no combinam
com um conjunto especfico de outra tabela. Seu comportamento o oposto do
comportamento de uma juno normal, o termo anti-join usado para descrever esta
operao. Anti joins normalmente so expressados usando subconsultas.
Anti Join com NOT IN
A forma mais natural de se expressar um anti join utilizando NOT IN. Por exemplo a
consulta abaixo retorna employees que no so customers:
Select surname, firstname, date_of_birth
From employees
Where (surname, firstname, date_of_birth) not in
(contact_surname, contact_firstname, date_of_birth from customers)
Este tipo de consulta executado ineficientemente pelo otimizador baseado em regra.
Neste exemplo o otimizador baseado em regra ir realizar um full table scan de customers
para cada linha em employees. Se nenhuma linha que combine com ela for encontrada, ento a
linha de employees retornada. O otimizador baseado em regra no utilizar ndice sobre
customers porque no existe uma clusula WHERE na subconsulta, o plano de execuo da
consulta ficar assim:

Rows
---------

Execution Plan
----------------------------------------0
SELECT STATEMENT HINT: RULE
800
FILTER
800
TABLE ACCESS GOAL: ANALYZED (FULL) OF EMPLOYEES
80000000
TABLE ACCESS GOAL: ANALYZED (FULL) OF CUSTOMERS
Nested table scans

Como existem 800 linhas em employees e cerca de 100000 linhas em customers,


processado 80 milhes (800*100000) linhas de customers.
Felizmente, o otimizador baseado em custo habilidoso para tirar vantagem de ndices
sobre a tabela CUSTOMERS e pode evitar os nested table scans. O plano de execuo do
otimizador baseado em custo ficar da seguinte forma:
Rows
---------

Execution Plan
----------------------------------------0
SELECT STATEMENT GOAL: CHOOSE
800
FILTER
800
TABLE ACCESS GOAL: ANALYZED (FULL) OF EMPLOYEES
800
INDEX GOAL: ANALYDED (RANGE SCAN) OF
SURNAME_FIRSTNAME_DOB (NON_UNIQUE)

Esta forma de execuo bem mais eficiente. O otimizador baseado em regra requer a
leitura de quase um milho de blocos para resolver o exemplo, onde o otimizador baseado em
custo requer bem menos. O otimizador baseado em regras no resolve NOT IN de forma
37

eficiente, quando utilizando otimizao baseada em regra, deve-se utilizar outra forma de antijoin tal como NOT EXISTS.
Anti Join com NOT EXISTS
A consulta anterior com NOT EXISTS fica da seguinte forma:
select surname, firstname, date_of_birth
From employees
Where not exists
( Select * from customers
where contact_surname = employees.surname
and contact_firstname = employees.firstname
and date_of_birth = employees.date_of_birth )
Usando-se este estilo de consulta, o otimizador busca uma linha que combine com
customers para cada linha em employees. Como existe uma clusula WHERE tanto o
otimizador baseado em custo quanto o em regra podem usar ndices que estejam disponveis.
Ambos os otimizadores escolhem um plano de execuo como o seguinte (embora possam
escolher ndices diferentes caso haja mais de um disponvel):
Rows
---------

Execution Plan
----------------------------------------0
SELECT STATEMENT GOAL: CHOOSE
800
FILTER
800
TABLE ACCESS GOAL: ANALYZED (FULL) OF EMPLOYEES
800
INDEX GOAL: ANALYZED (RANGE SCAN) OF
SURNAME_FIRSTNAME_DOB (NON_UNIQUE)

Pode-se ver que este plano equivalente ao plano anterior usando NOT IN com o
otimizador em custo. O otimizador baseado em custo trata NOT IN e NOT EXISTS da mesma
forma. No entanto, o otimizador baseado em regra ir resolver consultas com NOT EXISTS
de forma mais eficiente que consultas com NOT IN.
4. Otimizando Ordenao e Agrupamento
Neste captulo sero vista melhorias na performance de consultas as quais requerem
que o Oracle ordene ou agrupe dados.
Oracle pode precisar ordenar dados como resultado de uma requisio explcita para
retornar dados ordenados (por exemplo, quando se usa a clusula ORDER BY) ou como
resultado de uma operao intermediria realizada internamente a qual requer que os dados
estejam classificados em uma certa ordem (por exemplo, INTERSECT). Classificao de
dados pode consumir muito recurso computacional e ter um grande efeito sobre a performance
de consultas. Saber quando Oracle realiza ordenaes uma forma de evitar desperdcios de
recursos e de tempo, melhorando o desempenho de consultas.
O operador GROUP BY agrupa linhas com valores comuns e retorna um resumo das
linhas para cada grupo. Operaes de agrupamento quase sempre envolvem ordenao.
Ordenao uma das operaes mais comuns realizadas por computadores,
especialmente quando se est recuperando dados. Vrias operaes requer que o Oracle
ordene dados, dentre elas esto:
38

Criao de ndice.
Agrupamento ou agregao de dados atravs dos comandos ORDER BY ou
DISTINCT.
Retornar dados ordenados como resultado de uma consulta que utiliza ORDER
BY.
Juno de tabelas ou result sets usando o mtodo sort merge.
Realizar certas subconsultas.
Ordenaes desnecessrias
possvel causar ordenaes indesejveis como resultado de operaes. Isto pode
acontecer por duas razes[5]:
Uso desnecessrio da clusula DISTINCT. Quase sempre DISTINCT utiliza
ordenao para eliminar valores duplicados. Algumas vezes inevitvel o seu uso,
mas muitas vezes pode ser evitado. Assim, ao usar a clusula DISTINCT deve-se
ter em mente que um overhead extra ser necessrio para a ordenao.
Usando UNION em vez de UNION ALL. O operador UNION ordena o resultado
para eliminar linhas duplicadas. UNION ALL no elimina os valores duplicados,
portanto no necessita ordenao. Assim, deve-se utilizar UNION apenas quando
realmente importante no ter resultados duplicados na consulta.
Contando o nmero de linhas em uma tabela
Uma operao de agrupamento bastante utilizada a funo COUNT, usada para contar
o nmero de linhas em uma tabela, para isso pode-se utilizar COUNT(*), COUNT(0) ou
COUNT(coluna). Qual seria a melhor opo?
Quando contando linhas onde pode-se usar um ndice sobre uma coluna nica,
normalmente uma melhor opo que o COUNT(*), pois o ndice quase sempre menor que
a tabela. COUNT(*) deve ser usado em preferencia a COUNT(0) ou
COUNT(coluna_no_indexada), pois o Oracle realiza algumas otimizaes quando a
expresso COUNT(*) encontrada.
GROUP BY
A clusula GROUP BY em um comando SQL pode ser usado para agrupar valores de
uma coluna, agrupando linhas por valor encontrado na coluna.
Normalmente um GROUP BY resolvido por um full table scan, contudo este acesso
pode ser evitado se existe um ndice disponvel para resolver o GROUP BY, este ndice dever
conter as colunas da lista do GROUP BY e todas as colunas agregadas na lista do SELECT.
Por exemplo, para a consulta abaixo utilizar um ndice, este dever conter
department_id e salary.
select department_id, count(*), min(salary), max(salary)
from employees
group by department_id
A Clusula HAVING
A clusula HAVING usada para eliminar linhas de um GROUP BY antes que elas
sejam agrupadas, ele uma condio de filtro que atua depois da agregao. Uma observao
a ser feita com relao ao uso do HAVING que como ele elimina linhas depois da agregao
deve-se usar preferencialmente a clusula WHERE para eliminar linhas. O HAVING deve ser
usado apenas com funes de grupo, o uso da clusula WHERE em vez do HAVING para

39

eliminar linhas permite que um menor nmero de linhas participe da juno e da ordenao,
melhorando a utilizao de recursos.
O exemplo abaixo mostra o uso de HAVING com uma funo de grupo:
select department_id, count(*), min(salary), max(salary)
from employees
group by department_id
having count(*) > 4

5. Concluso
A otimizao de consultas apenas um dos vrios aspectos que devem ser
considerados quando deseja-se construir uma aplicao de acesso a um banco de dados bem
otimizada. Para se conseguir melhores resultados critrios de desempenho devem ser
considerados nas fazes iniciais do desenvolvimento de software. Com isso tambm evita-se que
seja necessrio um grande esforo com re-projeto ou re-codificao para se atingir um nvel de
desempenho satisfatrio, e nem sempre consegue-se o mesmo resultado que se teria
conseguido se os critrios de performance fossem considerados desde o incio do
desenvolvimento.
Otimizar uma consulta no uma tarefa fcil. Mesmo utilizando-se todas as tcnicas
disponveis, existem casos que fogem regra. A consulta ser executada por um programa, e
como tal est suscetvel a falhas, seja por um mal entendimento dos dados ou por alguma
deficincia do algoritmo usado pelo SGBD. Quando, mesmo utilizando todas as tcnicas
disponveis, a consulta continua seguindo um caminho de execuo que no corresponde s
expectativas, o Oracle possibilita que se guie a execuo atravs do uso de hints.
Mesmo utilizando-se tudo que est disponvel para otimizar a consulta, nunca deve-se
dispensar testes em ambientes com volumes de dados diferentes e que reflita a realidade atual e
futura do sistema, principalmente no caso de consultas de grande impacto. Assim, assegura-se
que consultas hoje perfeitas continuem funcionando corretamente no futuro.
Outros aspectos tais como o projeto da aplicao, o projeto fsico do banco de dados,
requisitos de hardware, upgrades, dentre outros, tambm devem ser considerados na
otimizao de uma aplicao. Alguns aspectos esto ligados diretamente ao banco de dados.
Por exemplo, no projeto fsico do banco de dados que decises como, agrupar vrias tabelas
em uma ou desagrup-las, de forma a beneficiar a alterao ou a recuperao de dados, devem
ser tomadas. Aspectos como, a otimizao de comandos que manipulam dados (insert, update,
delete), otimizao de transaes, SQL Paralelo, SQL Distribudo e o compartilhamento de
comandos SQL, o qual possibilita minimizar o acesso ao disco, melhorando a taxa de acerto
com que os dados so recuperados da memria, poderiam ter sido abordados neste trabalho,
no o foram por fugirem ao escopo principal do mesmo, mas podero ser vistos num trabalho
futuro.

40

6. Referncias
[1]

Guy Harrison, Oracle SQL High-Performance Tuning, Prentice Hall, 1997.

[2]

Richard J. Niemiec, Oracle Performance Tuning Tips & Tecniques, McGraw-Hill,


1999.

[3]

Ramez Elmasri, Shamkant B. Navathe, Fundamentals of Database Systems, AddisonWesley, 1999.

[4]

Oracle8TM Indexing Strategies,


http://otn.oracle.com/products/oracle8/htdocs/xo814twp.htm

[5]

Advanced Topics: SQL Efficiency, http://www.dragonlee.co.uk/adv01.html

[6]

Execution Plan Efficiency, http://www.dragonlee.co.uk/adv02.html

[7]

Indexing, http://technet.oracle.com/doc/inter.815/a67845/ind.htm

[8]

http://www.uaex.edu/srea/

[9]

http://www.orafaq.com/faq.htm

[10]

http://otn.oracle.com/

41