Sie sind auf Seite 1von 7

Instrues para Tuning de SQL

1. Padronizao na escrita de SQLs:

Cada comando SQL processado basicamente em trs fases: Anlise (parse) Execuo (execute) Retorno das linhas selecionadas (fetch).

A padronizao na escrita de SQLs permite a reutilizao dos mesmos, inclusive por diferentes sesses e usurios, diminuindo sensivelmente o tempo e o consumo de recursos na realizao do parse (verificao sinttica, semntica e montagem do plano de acesso) dos comandos. O objetivo no ter 300 usurios utilizando o mesmo SQL, mas ter um mesmo SQL, que executado 300 vezes ou mais, sendo reutilizado todas as vezes. Assim, abaixo vo algumas instrues para atingir este objetivo: a) b) c) padronizao no uso de maisculas/minsculas: recomendamos utilizar sempre maisculas. padronizao no uso de espaos em branco entre as clusulas do comando: recomendamos utilizar sempre 1 (um) espao em branco. utilizao de bind variables ao invs de literais concatenados s clusulas do comando. Essa a instruo mais importante quanto formao do SQL, uma vez que o mesmo comando, se construdo sem as bind variables, passar pelo processo de parse cada vez que for executado, como no exemplo a seguir:
SELECT PESS_NOME FROM PESSOAS WHERE PESS_IDEN = 1; SELECT PESS_NOME FROM PESSOAS WHERE PESS_IDEN = 2;

Devendo ser utilizada a seguinte forma:


SELECT PESS_NOME FROM PESSOAS WHERE PESS_IDEN = :V_IDEN;

Ou, no caso de utilizao de JDBC, da seguinte forma:


SELECT PESS_NOME FROM PESSOAS WHERE PESS_IDEN = ?;
Marcelo Ferreira - marcelo-f@bol.com.br

Alm disso, o nome e o tipo das bind variables devem ser iguais entre 2 comandos. O exemplo a seguir ilustra esse caso:
SELECT PESS_NOME FROM PESSOAS WHERE PESS_IDEN = :V_IDEN; SELECT PESS_NOME FROM PESSOAS WHERE PESS_IDEN = :V_ID;

As formaes acima no so reutilizadas entre si, devendo ser utilizada somente a seguinte forma:
SELECT PESS_NOME FROM PESSOAS WHERE PESS_IDEN = :V_IDEN;

No caso do JDBC, no informado o nome. Internamente, os ? so substitudos por : 1, :2, etc, o que garante que os nomes sero os mesmos. Mas o tipo de atribuio usado, setInt ou setLong por exemplo, faz diferena, e o SQL pode no ser reutilizado.

2.

Evitar o uso de sentenas do tipo SELECT * FROM TABELA:

Em lugar disso, procurar definir sempre as colunas que vo ser necessrias. Isso evitar que dados no necessrios sejam transferidos do Banco de Dados para a aplicao, alm de garantir que uma eventual alterao na tabela no cause uma interrupo no funcionamento do SQL. Assim, utilizar uma formao como segue:
SELECT PESS_NOME, PESS_DATA_NASC FROM PESSOAS;

3.

Fazer uso de procedures, functions e triggers:

Em operaes que demandam um grande nmero de acessos ao Banco de Dados, retornando para a aplicao um pequeno numero de linhas, deve-se fazer uso de procedures ou functions de Banco de Dados. Por exemplo: rotinas de cpia de tabelas, atualizaes em lote, relatrios complexos, etc. Em operaes que podem ser executadas automaticamente pelo Banco de Dados, utilizar triggers. Por exemplo: totalizao de campos, replicao de campos, gravao de tabelas de histricos, etc.

4.

Evitar o uso de funes nas clusulas WHERE:

O uso de funes nas clusulas WHERE pode impedir a utilizao de ndices no acesso s tabelas. Por exemplo:
Marcelo Ferreira - marcelo-f@bol.com.br

SELECT PESS_NOME FROM PESSOAS WHERE TO_CHAR(PESS_DATA_NASC,YYYYMMDD) = :DATA_NASC;

Esse comando no utilizaria um ndice que porventura existisse na coluna PESS_DATA_NASC, devendo ser utilizada a seguinte forma:
SELECT PESS_NOME FROM PESSOAS WHERE PESS_DATA_NASC = TO_DATE(:DATA_NASC,YYYYMMDD);

Alm disso, o uso de funes para formatao das colunas selecionadas deve ser substitudo por tratamento especfico no prprio programa. Isso garante uma certa independncia do Banco de Dados utilizado, alm de aliviar o processamento por parte do Banco de Dados. Por exemplo:
SELECT DECODE(COL1,1,Compra,2,Aluguel,...) INTO :V_TIPO FROM TABELA1;

Deve ser substitudo por:


SELECT COL1 INTO :V_COL1 FROM TABELA1;

E, no programa, fazer um tratamento apropriado do tipo:


CASE V_COL1 WHEN 1 THEN V_TIPO := Compra WHEN 2 THEN V_TIPO := Aluguel WHEN 3 THEN V_TIPO := Leasing ...

5.

Evitar o uso de expresses com operandos de tipos diferentes:

Em expresses cujos operandos so de tipo diferente, por exemplo:


SELECT COL2 FROM TABELA1 WHERE COL1 = 1;

Onde COL1 definida do tipo CHAR(1), uma converso implcita sempre ocorre, e essa expresso transformada para:
SELECT COL2 FROM TABELA1 WHERE TO_NUMBER(COL1) = 1;

Com isso, qualquer ndice que exista na COL1 deixar de ser utilizado. Deve ser utilizada a seguinte forma:
Marcelo Ferreira - marcelo-f@bol.com.br

SELECT COL2 FROM TABELA1 WHERE COL1 = TO_CHAR(1);

6.

Uso de clusulas IN versus EXISTS:

Via de regra, o que deve direcionar o uso dessas clusulas a comparao entre a quantidade de registros que deve retornar na subquery e a quantidade de registros que deve retornar na query externa, ou seja, qual das clusulas WHERE mais seletiva. Por exemplo:
SELECT D.ID, D.CREDOR FROM DOCUMENTOS D WHERE EXISTS (SELECT NULL FROM PARCELAS P WHERE P.DOC_ID = D.ID AND P.VENCIMENTO = TO_DATE(:V_DATA,YYYYMMDD));

Supondo que exista um ndice na coluna DOC_ID da tabela PARCELAS, o plano de execuo para o comando anterior fazer uma leitura total (full table scan) na tabela DOCUMENTOS, pois a clusula WHERE pouco seletiva, no indicando uso de nenhum ndice, e depois fazer uma leitura pelo ndice em DOC_ID na tabela PARCELAS. Supondo que exista um ndice na coluna VENCIMENTO da tabela PARCELAS, o SQL poderia ser escrito usando a clusula IN, forando o plano de execuo a fazer primeiro uma leitura pelo ndice em VENCIMENTO na tabela PARCELAS, que mais seletivo, retornando poucas linhas, e depois fazer uma leitura pelo ndice em ID na tabela DOCUMENTOS, uma vez que a clusula WHERE agora indica a utilizao do mesmo.
SELECT D.ID, D.CREDOR FROM DOCUMENTOS D WHERE D.ID IN (SELECT DOC_ID FROM PARCELAS P WHERE P.VENCIMENTO = TO_DATE(:V_DATA,YYYYMMDD));

7.

Reduzir o nmero de chamadas ao Banco de Dados:

Quando apropriado, utilize INSERT, UPDATE, ou DELETE ... RETURNING ... para atualizar e selecionar dados com uma nica chamada. Alm de otimizar o acesso ao Banco de Dados, diminui o trfego na rede. Veja um exemplo:
DELETE FROM TABELA1 WHERE COL1 = :V_COL1 RETURNING COL2, COL3;

8.

Evitar o uso de clusulas GROUP BY, ORDER BY e DISTINCT:


Marcelo Ferreira - marcelo-f@bol.com.br

O uso dessas clusulas sempre provoca a leitura de todas as linhas que satisfazem a clusula WHERE do SQL, a sua classificao, e, somente depois, o retorno das mesmas para a aplicao. Muitas vezes o uso dessas clusulas exigido pelo projeto das tabelas e necessidades da aplicao. Porm, na maioria das vezes, existem alternativas para evitar o seu uso. A clusula ORDER BY, por exemplo. uma boa alternativa descarregar os dados desordenados dentro de uma tabela interna e, depois, efetuar a classificao nessa tabela interna segundo os critrios requeridos, que poderiam ser variveis, sem a necessidade de fazer nova chamada ao Banco de Dados. J a clusula DISTINCT, muitas vezes, denota a falta de uma join condition na clusula WHERE, ou seja, devido a uma falha na composio das join conditions o SQL retorna linhas repetidas, e, para resolver, coloca-se o DISTINCT. Isso um erro grave, e deve ser evitado.

9.

Ateno especial clusula WHERE:

Podemos dizer que existem dois tipos de condies a serem codificadas na clusula WHERE: join conditions e filter conditions. As join conditions so as condies de ligao e correspondncia entre duas tabelas. Normalmente so montadas em cima de foreign keys e tem boa chance de serem atendidas por ndices. Exemplo: WHERE P.DOC_ID = D.ID; J as filter conditions so as condies de filtro aplicadas a uma tabela de cada vez. Exemplo: WHERE P.VENCIMENTO = TO_DATE(:V_DATA,YYYYMMDD). Assim, importante que as join conditions sejam as primeiras a serem codificadas e contemplem todas as colunas que compem a ligao entre as tabelas, ou seja, todas as colunas da foreign key. Isso facilita muito a codificao da clusula WHERE e garante que no resultar um produto cartesiano indesejado. A ordem das join conditions tambm importante, sendo que as colunas da tabela direcionadora (driving table) devem aparecer esquerda nas comparaes e os joins mais seletivos devem aparecer primeiro. No exemplo a seguir, a driving table a TABA, supondo ser a que apresenta maior seletividade na aplicao da filter condition:
SELECT INFO FROM TABA A, TABB B, TABC C WHERE A.KEY1 = B.KEY1
Marcelo Ferreira - marcelo-f@bol.com.br

AND AND AND AND

A.KEY2 A.ACOL B.BCOL C.CCOL

= C.KEY2 BETWEEN :ALOW AND :AHIGH BETWEEN :BLOW AND :BHIGH BETWEEN :CLOW AND :CHIGH;

Normalmente, a escolha da driving table e do driving index baseada na aplicao das filter conditions. Assim, tabelas que apresentam menor cardinalidade efetiva, ou seja, suas chaves apresentam maior nmero de valores e menor nmero de ocorrncias com o mesmo valor, so candidatas a serem a driving table. s vezes conveniente efetuar um estudo do contedo da tabela, a fim de obter um conhecimento maior do estado dos dados dentro da mesma. Isto pode auxiliar bastante na codificao da clusula WHERE. Como ltima recomendao, vale ressaltar que para garantir a utilizao de algum ndice, a clusula WHERE deve contemplar pelo menos a primeira coluna do ndice. No adianta informar as outras colunas, se a primeira no estiver na clusula WHERE, o ndice no ser usado.

10.

Sempre usar o EXPLAIN PLAN:

muito importante que seja gerado e revisto o plano de execuo de todos os SQLs para garantir uma boa performance. E essa operao feita em duas etapas. Para gerar o plano de execuo, usamos o comando EXPLAIN PLAN, cujo formato o seguinte:
EXPLAIN PLAN SET STATEMENT_ID = 'XXX' FOR SQL a ser examinado;

Para verificar o plano gerado, o comando o seguinte:


SELECT LPAD(' ',2*(LEVEL-1))||OPERATION||' '||OPTIONS|| ' '||OBJECT_NAME||' '||DECODE(ID, 0, 'COST = '|| POSITION) "QUERY PLAN" FROM PLAN_TABLE START WITH ID = 0 AND STATEMENT_ID = 'XXX' CONNECT BY PRIOR ID = PARENT_ID AND STATEMENT_ID = 'XXX';

A dica salvar esses comandos em arquivos (scripts) de fcil acesso para serem executados a partir do SQL Plus. Os nomes dos arquivos poderiam ser ExplainPlan.sql e
Marcelo Ferreira - marcelo-f@bol.com.br

ConsultaPlan.sql. E para que se possa fazer novo EXPLAIN com os mesmos scripts, acrescentar ao script de consulta o seguinte comando:
DELETE FROM PLAN_TABLE WHERE STATEMENT_ID = 'XXX';

importante lembrar que o plano de execuo gerado deve ser examinado com cuidado e avaliado segundo algumas premissas. Por exemplo, nem sempre um table full scan ruim. No caso de tabelas pequenas, ele at desejado. O acesso por ndice nem sempre a melhor alternativa. No caso de ser necessrio acessar todas as linhas de uma tabela, o table full scan pode apresentar melhor resultado. O fundamental observar possveis falhas na construo do SQL, por exemplo, se um ndice que deveria estar sendo usado no est devido falta de uma join condition.

Marcelo Ferreira - marcelo-f@bol.com.br