Anda di halaman 1dari 55

Tuning SQL

Gediel Luchetta
Infra-Estrutura Oracle
Agenda

1. Entender como um comando SQL é processado


2. Tipos de otimizadores do Oracle
3. Compreendendo e coletando estatísticas
4. Métodos de acessos
5. Técnicas de Joins
6. Verificando e entendendo um plano de acesso
7. Influenciando o Otimizador (Hints)
8. Funcionalidades de Performance
9. Dicas práticas de otimização de sistemas OLTPs
10. Dicas práticas de otimização de sistemas Batchs/DSSs
1. Entender como um comando SQL é
processado

Fases do comando SQL.

OPEN CLOSE

PARSE BIND EXECUTE FETCH


1. Entender como um comando SQL é
processado
Parse:
1. Procura pelo comando na shared pool (função hash);
2. Verifica a sintaxe : definida para e linguagem SQL;
3. Verifica a semântica: verifica se todos os objetos referenciados
são válidos e se os requisitos de segurança são respeitados.
4. Resolve definição de views e subquerys: tenta otimizar o
comando, transforma joins em subquerys, in em diversos Or, etc.
5. Determina o plano de execução: Determina o plano e armazena
na shared pool.
1. Entender como um comando SQL é
processado

Bind: Nessa fase o server percorre o comando para encontrar


variáveis binds, que serão substituídas pelos seus
respectivos valores.

Execute: Aplica o plano de execução feito na fase de parse,


executa os I/Os e sorts necessários para o DML.

Fetch: Retorna as linhas processadas. Usado somente para


comando "select".
1. Entender como um comando SQL é
processado

Área de SQL compartilhado (Shared Pool)


• Comando em
forma de
parse;
SGA
• Plano de
Shared Pool execução;
• Objetos
Cursor1 Cursor2 referenciados.

Usr A Usr B Usr C

Select Select Select


Cursor2 Cursor1 Cursor2
1. Entender como um comando SQL é
processado

• Compartilhamento de cursores: Quando o Oracle encontra


um comando exatamente igual na shared pool ele tem
condições de reaproveitá-lo (soft parse).

• Benefícios:
• Reduz o tempo de parse;
• Reduz consumo de cpu do server;
• Melhor uso da memória;
• Cache comandos SQL mesmo que esses estejam
dentro das aplicações.
1. Entender como um comando SQL é
processado

• Exigências para compartilhamento:


– Somente comandos Idênticos podem ser compartilhados;
– O texto deve ser idêntico, incluindo Upper ou Lower, espaços em
branco e comentários;
– Os objetos referenciados devem ser iguais e as variáveis binds
devem ser do mesmo tipo.

• Obs: Ferramentas Oracle (forms,reports,precomp,pl/sql)


procuram automaticamente deixar os comandos iguais
com variáveis bind, upper, retirada de espaços e
comentários, etc.
1. Entender como um comando SQL é
processado

• Recomendações para compartilhamento de


cursores:
– Usar código compartilhado:
• Usar packages, procedure e funções de banco;
– Utilizar padrões para programação:
• Upper ou lower case;
• Espaços em brancos;
• Comentários;
• Variáveis Bind.
2. Tipos de otimizadores

Processo de otimização:

• Para retornar as linhas de uma consulta existem diversos caminhos


possíveis, todos trazendo o mesmo resultado;

• Como o SQL é uma linguagem declarativa a responsabilidade de


escolher esse caminho fica para o banco de dados;

• A escolha do "melhor caminho” (plano de execução) é feita na fase


parse pelo Oracle;

• Tipos de otimização disponíveis no Oracle:


Regra : baseado numa tabela ranking (descontinuado)
Custo : baseado em estatísticas do banco.
2. Tipos de otimizadores

Otimizador baseado em Regra (RBO):


• Verifica todas as possibilidades de acesso e atribui um ranking para
cada uma;

• A possibilidade com o menor ranking é escolhida como plano de


execução;

• Não leva em consideração os dados na base;

• Oracle 9i r2 é o último release com otimizador por regra;

• Sumário do ranking por regra:


• Índices são sempre preferíveis do que full table scan;
• Busca por igualdade é sempre melhor que busca por intervalos;
• Intervalos fechados são melhores que intervalos abertos (> ou < );
• Índices de várias colunas são melhores que em coluna única.
2. Tipos de otimizadores

Otimizador baseado em Custo (CBO):


• Avalia várias possibilidades de trazer os dados (planos);
• Procura calcular um “custo” para cada plano;
• O plano de menor “custo” é escolhido;
• Está sendo continuamente aperfeiçoado a cada versão do Oracle;
• O plano pode mudar conforme o crescimento da base;
• Possibilidade de considerar a seletividade das colunas
(histogramas);
• Para ser utilizado corretamente deve existir estatísticas coletadas
para os objetos.

Obs: na prática, nem sempre o menor custo é o melhor plano.


2. Tipos de otimizadores

Principais fatores considerados no cálculo do custo de um


plano:
• Número estimado de leituras na base de dados;
• Utilização de CPU;
• Exigências de sorts;
• Possibilidade de utilizar parallel query;
3. Compreendendo e coletando estatísticas

• Coletando estatísticas para o Otimizador:


– Comando ANALYZE;
– Package DBMS_STATS (somente p/ 8i e acima)
• Exemplo do comando analyze:
– Analyze table clientes compute statistics;
– Analyze table cliente estimate statistics sample 20
percent;
– Analyze table produtos delete statistics;
– exec dbms_stats.gather_schema_stats (ownname =>
‘SCOTT’);
– exec dbms_stats.gather_table_stats (ownname =>
‘SCOTT’, tabname => ‘EMP’);
3. Compreendendo e coletando estatísticas

• Verificando as estatísticas:

Select table_name, last_analyzed, num_rows


From user_tables;

Select index_name, last_analyzed, num_rows,


num_distinct
From user_indexes;
4. Métodos de acessos

• Full table Scan:


– Pode usar multiblock I/O;
– Pode ser Paralelizado.
• Index Scan:
– Acesso apenas ao índice;
– Acesso a tabela pelo rowid.
• Fast Full Index Scan:
– Pode usar multiblock I/O;
– Pode ser Paralelizado.
4. Métodos de acessos

Índices:
• Índices são usados para agilizar o processo de
consulta ao banco de dados;
• Sua utilização tem custos:
– aumenta o tempo dos inserts, updates e deletes;
– Consumem espaço no banco de dados;
– As leituras sempre são feitas bloco a bloco;
• Devem ser muito bem planejados;

Ps: restrições tipo “is null” ou “is not null” nunca usam índices.
4. Métodos de acessos

Full Scans:
Tabela de clientes:
Nro de linhas : 1640
Nro de blocos : 40
Tamanho do bloco : 4k
Tamanho da tabela : 160K

I/O 1 I/O 2 I/O 3 I/O 4 I/O 5

Parametro do banco:
1 Bloco
DB_FILE_MULTIBLOCK_READ_COUNT = 8
4. Métodos de acessos

Pergunta:
Qual é o melhor método de acesso, Index
lookups ou Full Scans?

Resposta:
Depende......
5. Técnicas de Joins

• NESTED LOOP
• SORT MERGE JOIN
• HASH JOIN
5. Técnicas de Joins

• Nested Loops join:


1. Uma tabela é definida como outer table e a outra como
inner table;
2. Para cada linha selecionada da outer table todas as linhas
da inner table são buscadas;

NESTED LOOPS
TABLE ACCESS (...) OF outer_table
TABLE ACCESS (...) OF inner_table

NESTED LOOPS
TABLE ACCESS (BY ROWID) outer_table
INDEX (...SCAN) OF outer_table_index (...)
TABLE ACCESS (BY ROWID) inner_table
INDEX (...SCAN) OF inner_table_index (...)
5. Técnicas de Joins

• Sort Merge join:


1. Para cada tabela as linhas que satisfaçam os
nonjoin predicados são recuperadas;
2. Cada um dos conjuntos é ordenado pelas colunas
do join (sort);
3. Os dois conjuntos são comparados e apenas as
linhas que combinam são selecionadas (merge);
4. Parâmetros do banco: sort_area_size e
sort_area_retained_size.
MERGE (JOIN)
SORT (JOIN)
TABLE ACCESS (...) OF tableA
SORT (JOIN)
TABLE ACCESS (...) OF tableB
5. Técnicas de Joins

• Hash join:
1. A menor tabela é usada para construção de uma
“hash table”;
2. A maior tabela é então acessada e comparada
com a “hash table”;

HASH JOIN
TABLE ACCESS (...) OF tableA
TABLE ACCESS (...) OF tableB

• Obs: todos esses joins podem ser “outer join”


5. Técnicas de Joins

• Hash join: ---


--
--- ---
-- --
Resultado
--- Hash Table
--- ---
-- --- -- --
---
--- ---
-- ---
--- -- --
---
--- ---
-- --
---
5. Técnicas de Joins

Pergunta:
Qual é o melhor tipo de Join, nested loops,
Sort Merge Join ou Hash Join?

Resposta:
Entre Hash Join e Sort Merge Join o
primeiro é preferível.
Entre Hash Join e Nested loops, depende...
6. Verificando e entendendo um plano de acesso

• Explain Plan:

– Utilitário que mostra o plano que o Oracle


usaria para resolver um comando SQL.
– O plano de execução é inserido numa tabela
chamada "plan table" a qual deve ser
consultada para se extrair o plano.
6. Verificando e entendendo um plano de acesso

• Sintaxe do Explain plan:

explain plan [set statement_id = <'id para o


comando'>]
[into <nome da tabela>]
for comando_sql;
6. Verificando e entendendo um plano de acesso

• Formatando a saída da plan_table:

select rtrim(lpad(' ',2*level) ||


rtrim(operation) ||' ' ||
rtrim(options) ||' ' ||
rtrim(object_name) ||' ' ||
COST) "Plano de Execução"
from plan_table
connect by prior id=parent_id
start with id=0;
6. Verificando e entendendo um plano de acesso

Exemplo de explain plan (carregando a plan_table):


6. Verificando e entendendo um plano de acesso

Exemplo de explain plan (visualizando o plano):


6. Verificando e entendendo um plano de acesso

• Princípios para Interpretar a saída do explain plan:


1. Os níveis mais internos são executados primeiro;
2. Se duas linhas estiverem no mesmo nível, a que
estiver mais acima é executada antes;
3. Um caminho de acesso pode ser composto de
vários passos.
Por exemplo: geralmente um "INDEX SCAN"
aparecerá junto com um "TABLE SCAN BY ROWID".
Esses dois procedimentos devem ser considerados
um único passo no plano de execução.
6. Verificando e entendendo um plano de acesso

SELECT STATEMENT MODE: ALL_ROWS


SORT (AGGREGATE) (5)
HASH JOIN (4)
TABLE ACCESS MODE: ANALYZED (FULL) OF 'GI_CLIENTES_IMPRESCINDIVEIS' (TABLE) (3)
NESTED LOOPS (2)
INDEX MODE: ANALYZED (FAST FULL SCAN) OF 'SGD_INSTALACION_XI_I11' (INDEX) (1)
INDEX MODE: ANALYZED (RANGE SCAN) OF 'PK_SGD_INST_PADRE_XI' (INDEX (UNIQUE)) (2.1)

SELECT STATEMENT MODE: ALL_ROWS


SORT (UNIQUE) (8)
UNION-ALL (7)
NESTED LOOPS (2)
TABLE ACCESS MODE: ANALYZED (BY INDEX ROWID) OF 'SGD_INSTALACION' (TABLE) (1.1)
INDEX MODE: ANALYZED (RANGE SCAN) OF 'SGD_INSTALACION_XI_I99' (INDEX) (1)
TABLE ACCESS MODE: ANALYZED (BY INDEX ROWID) OF 'SGD_LLAVE' (TABLE) (2.2)
INDEX MODE: ANALYZED (UNIQUE SCAN) OF 'PK_SGD_LLAVE_XI' (INDEX (UNIQUE)) (2.1)
HASH JOIN (5)
TABLE ACCESS MODE: ANALYZED (BY INDEX ROWID) OF 'SGD_INSTALACION' (TABLE) (3.1)
INDEX MODE: ANALYZED (RANGE SCAN) OF 'SGD_INSTALACION_XI_I08' (INDEX) (3)
TABLE ACCESS MODE: ANALYZED (FULL) OF 'SGD_LLAVE' (TABLE) (4)
TABLE ACCESS MODE: ANALYZED (BY INDEX ROWID) OF 'SGD_INSTALACION' (TABLE) (6.1)
INDEX MODE: ANALYZED (RANGE SCAN) OF 'SGD_INSTALACION_XI_I99' (INDEX) (6)
7. Influenciando o Otimizador (Hints)

• Sugestões para direcionar o otimizador na escolha do melhor plano.


• O desenvolvedor da aplicação possui maiores conhecimentos dos dados
que o otimizador.
• Hints são aplicados apenas nos comandos em que aparecem.
• A especificação de hints é feita no comando como uma espécie de
comentário:

Select Select
Insert Insert
/*+ HINT */ OU --+ HINT
Update Update
Delete Delete
7. Influenciando o Otimizador (Hints)

• Principais Hints para métodos de acessos:


– Full : /*+ full (tabela) */
– Index : /*+ index (tabela índice) */
– Index_asc : /*+ index_asc (tabela índice) */
– Index_desc : /*+ index_desc (tabela índice) */
– Index_ffs : /*+ index_ffs (tabela índice) */
– Use_concat : /*+ use_concat */
– Hash_aj : /*+ hash_aj */
– Merge_aj : /*+ merge_aj */
– Rule : /*+ rule */
– Ordered : /*+ ordered */
– Use_nl : /*+ use_nl (A,B) */
– Use_hash : /*+ use_hash (A B C) */
– Parallel : /*+ Parallel(A,4) */
– Append : /*+ Append */
– Leading : /*+ Leading(A) */
8. Funcionalidades de performance

Bulk Binds
SQL Dinâmico nativo
Materialized Views
Function Based Index
Novos DMLs
Cláusula With
8. Funcionalidades de performance

Bulk Binds
• Redução do overhead pela redução da troca de contexto em
pl/sql e sql;
• Operação com múltiplas linhas em um único DML;
• Adição de novas palavras chaves: FORALL e BULK
COLLECT.

PL/SQL ENGINE
PROCEDURAL
BLOCK PROCEDURAL STATEMENT
PL/SQL EXECUTOR

SQL ENGINE D
A
T
A
SQL STATEMENT EXECUTOR
8. Funcionalidades de performance

Exemplos de Bulk Binds:


1) Insert:
forall i in 1..1000
insert into clientes (tab_cod(i), tab_nome(i));
2) Update:
forall i in tab_fun.first..tab_fun.last
update funcionarios
set salario = salario * 1.1
where fun_id = tab_fun(i);
3) Delete:
forall i in tab_pro.first..tab_pro.last
delete from produtos
where pro_id = tab_pro(i);
8. Funcionalidades de performance

 SQL dinâmico nativo


Vantagens sobre dbms_sql:
• Melhor performance;
• Código mais “enxuto”;
• Fácil de programar;
• Fácil de compreender;
• Possibilidade de processar single-row ou
multi-row.
8. Funcionalidades de performance

 Exemplos de SQL dinâmico nativo:

string := ‘create table temp (col1 number, col2


date)’;
execute immediate string;
--
string := ‘insert into temp values (:1,:2)’;
execute immediate string using v_id, v_data;
--
string := ‘select col2 from temp where col1 = :1’;
execute immediate string into v_data using v_id;
8. Funcionalidades de performance

 Materialized Views:
– Utilizadas para armazenar dados pré-computados, agregados,
sumarizados etc;
– Aumentam a velocidade das querys em grandes bases;
– A atualização da materialized view é automática e transparente;
Exemplo:
create materialized view pedidos_clientes build immediate refresh
force enable query rewrite as
select c.cli_nome, sum(i.ite_qtd)
from pedidos p, itens_pedido i, clientes c
where c.cli_id = p.cli_id
and p.ped_id = i.ped_id
group by c.cli_nome;
8. Funcionalidades de performance

Function Based Index:


– Facilitam consultas que buscam valores
retornados por funções ou expressões;
– O valor da função é pré-computado e
armazenado no índice;
– Quando a função é alterada o índice fica
desabilitado;
– A tabela deve ser “analisada” após a criação
do índice;
8. Funcionalidades de performance

Exemplos de Function Based Index:


create index idx_nome on clientes (upper(cli_nome));
select * from clientes where upper(nome) like
‘MARIA%’;
--
create index idx_teste on teste (col1 + col2 * col3);
select * from teste where (col1 + col2 * col3) = 100;
--
Create index idx_nvl_col1 on teste (nvl(col1,0));
Select * from teste where nvl(col1,0) = 0;
8. Funcionalidades de performance

Novos DMLs:
Multi-Table-Inserts:
– Permite a inserção de dados em várias tabelas
em um único comando;
– Pode ser usando para transferir dados de
uma ou mais source tables para um conjunto
de outras tabelas;
– A performance melhora porque não há
necessidade de ler o source mais que uma
vez.
8. Funcionalidades de performance

Novos DMLs:
Multi-Table-Inserts (Incondicional):
INSERT ALL INTO product_activity VALUES(
today, product_id, quantity)
INTO product_sales VALUES(
today, product_id, total)
SELECT TRUNC(order_date) today, product_id,
SUM(unit_price) total, SUM(quantity),quantity
FROM orders, order_items
WHERE orders.order_id = order_items.order_id
AND order_date = TRUNC(SYSDATE)
GROUP BY TRUNC(order_date), product_id;
8. Funcionalidades de performance

Novos DMLs:
Multi-Table-Inserts (condicional):
INSERT ALL
WHEN product_id IN
(select product_id FROM promotional_items)
INTO promotional_sales
VALUES (product_id, list_price)
WHEN order_mode = 'online'
INTO web_orders
VALUES (product_id, order_total)
SELECT product_id, list_price, order_total,
order_mode FROM orders;
8. Funcionalidades de performance

Novos DMLs:
Multi-Table-Inserts (condicional - first):
INSERT FIRST
WHEN order_total> 10000 THEN
INTO priority_handling VALUES (id)
WHEN order_total > 5000 THEN
INTO special_handling VALUES (id)
WHEN order_total > 3000 THEN
INTO privilege_handling VALUES (id)
ELSE
INTO regular_handling VALUES (id)
SELECT order_total, order_id id FROM orders;
8. Funcionalidades de performance

 Novos DMLs:
Comando merge: Realiza um update se a chave existir
senão realiza um insert.

MERGE INTO customer C USING cust_src s


ON (c.customer_id = s.src_customer_id)
WHEN MATCHED THEN
UPDATE SET c.cust_address = s.cust_address
WHEN NOT MATCHED THEN
INSERT (customer_id, cust_first_name, ...)
VALUES (src_customer_id, src_first_name,
...);
8. Funcionalidades de performance

Cláusula With:

• Permite utilizar um “query block” várias vezes em


uma query complexa;
• Recupera o retorno da query e armazena na área
temporária;
• Especifica-se um nome para o “query block” e
referencia-se esse nome na query;
• Resolve o problema de tabela temporárias;
8. Funcionalidades de performance

• Cláusula With (exemplo):


Encontrar todos os departamentos que
possem o total de salários abaixo de 1/8
do total de salários de toda empresa.
8. Funcionalidades de performance

Cláusula With:
• Abordagem tradicional:
SELECT department_name, SUM(salary) AS dept_total
FROM employees, departments
WHERE employees.department_id =
departments.department_id
GROUP BY department_name HAVING
SUM(salary) > (
SELECT SUM(salary) * 1/8
FROM employees, departments
WHERE employees.department_id =
departments.department_id)
ORDER BY sum(salary) DESC;
8. Funcionalidades de performance

Cláusula With:
• Cláusula With (exemplo) usando with:
WITH
summary AS (
SELECT department_name, SUM(salary) AS dept_total
FROM employees, departments
WHERE employees.department_id =
departments.department_id
GROUP BY department_name )
SELECT department_name, dept_total
FROM summary
WHERE dept_total > (
SELECT SUM(dept_total) * 1/8
FROM summary )
ORDER BY dept_total DESC;
9. Dicas práticas de otimização de sistemas
OLTPs

1) Realizar consultas mais restritivas quanto possível;


2) Preferir “EXISTS” e não “IN”;
3) Evitar uso de DISTINCT (tentar resolver com EXISTS);
4) Quando for necessário “order by” de um grande conjunto de dados, procurar
fazer com índice;
5) Não implementar “consultas genéricas” (filtros artificiais e tabelas
desnecessárias no from) e sim montar o sql dinâmicamente;
6) Usar outer join corretamente e somente quando necessário;
7) Avaliar o uso de índices compostos;
8) Evitar aplicações do tipo “conecta/desconecta” a cada requisição;
9) Utilizar sempre variáveis bind;
10) Procurar não deixar dados de histórico na base;
10. Dicas práticas de otimização de sistemas
Batch/DSS

1) Só usar índice quando o número de linhas a ser pesquisado for baixo caso
contrário sempre preferir Full Scans;
2) Preferir “HASH JOINS” e não “NESTED LOOPS”;
3) Para deletes/updates de mais de 20% das linhas procurar fazer com CTAS
(create table as select);
4) Usar “Parallel Query” se tiver CPU e bom sistema de Disco;
5) Utilizar opção NOLOGGING p/ CTAS e criação de índices;
6) Evitar indexação de tabelas temporárias;
7) Quando um plano apresentar problemas conferir se as estatísticas estão
atualizadas;
8) Usar funções como DECODE ou CASE, para evitar acessos desnecessários;
9) Paralelizar a nível de aplicação quando não der a nível de banco;
10) Sempre que possível usar as features do 9i: Multi-table insert, merge, with, etc.

Anda mungkin juga menyukai