Beruflich Dokumente
Kultur Dokumente
GRADUAO EM
CINCIA DA COMPUTAO
CENTRO DE INFORMTICA
ANLISE
DE FORMAS DE OTIMIZAO
DE CONSULTAS
TRABALHO DE GRADUAO
Aluna:
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
11
11
11
12
16
16
17
20
20
23
24
24
28
29
30
32
33
33
35
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
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:
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
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.
Figura 1.3:
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
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
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
retonadas / uso
ndex
V5
V6
V7
V8
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
10
15
20
25
30
35
40
45
Blocos obtidos
15
17
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
YesNo011001
10100101
Indice bitmap
sobre own_home
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.
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.
200
400
600
800
1000
1200
Blocos lidos
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
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)
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)
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.
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
Figura 3.3: Melhoria da performance obtida pela criao de ndice para suportar a consulta hierrquica
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.
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
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
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
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
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:
Usar IN?
35
a execuo da subconsulta
No existe ndice disponvel No. Cada execuo da Sim.
A subconsulta
0,23
Join
0,03
S ubquery com IN
0,01
0,05
0,1
0,15
0,2
0,25
0,3
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
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]
[2]
[3]
[4]
[5]
[6]
[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