terça-feira, 8 de maio de 2012

Execução paralela de instruções SQL: Parallel Query, DML e DDL

Varias vezes encontramos consultas, processos ou atualizações em massa provocando um alto índice de custos para o ambiente de banco de dados, apesar de varias otimizações serem aplicadas o custo ainda é extremamente alto o que acaba prejudicando varios processos e rotinas. 

Então.. o que podemos fazer para diminuir este impacto? 

Já pensou em paralelismo? 

O Paralelismo, disponibilizado na versão enterprise do Oracle database, oferece a ideia de se quebrar uma tarefa em partes para que, em vez de um único processo fazer todo o trabalho, muitos processos possam executar simultâniamente as partes e no final apresentar um resultado único em menos tempo do que o executado por um único processo. 

A execução paralela proporcina melhorias no desempenho mediante a utilização otimizada dos recursos de hardware do servidor, ou seja, podemos utilizar todas as CPUs de um servidor em uma única atividade o que proporcionaria um ganho significativo no processo, por exemplo. Esta mesma distribuição pode ser realizada em um ambiente clusterizado(RAC), onde podemos utilizar, se necessário, os recursos de todos os nodes para uma única tarefa/processo. 

Contudo, quando implementado, devemos sempre ficar atentos ao consumo dos recursos do servidor como CPU, memória e discos, pois o paralelismo pode saturar completamente uma máquina, ficando então a cargo do DBA equilibrar cuidadosamente o número de pessoas que executam operações paralelas quanto o grau do paralelismo utilizado para que os recursos do servidor não sejam esgotados. 

Para a divisão e execução simultânia das varias partes de uma tarefa, o Oracle cria uma sessão “coordenador” que gerencia os processos escravos responsáveis pelas execuções paralelas e que ao termino recebe de cada escravo os resultados e reproduz uma saida combinada de forma a obtermos o mesmo resultado do que uma execução em serie, porem com o diferencial deste processo paralelo ter concluido muito mais rapidamente. 

O paralelismo pode ser especificado em 3 (três) diferentes níveis:

Nível de instrução: 

Utilizando hints

Nível de objeto: 

Especificando o grau de paralelismo na definição do objeto, tabela ou indice. 

Nível de instance: 

Ajustando as parametrizações da instance. (show parameter parallel)

Visto um básico histórico do funcionamento do paralelismo, vamos agora aprender sobre 3 tipos de paralelismo que são: Parallel Query, DML e DDL. 

Parallel Query: 

O paralelismo de queries, também conhecida como PQO (Parallel Query Option), foi a primeira feature de execução paralela desenvolvida pela Oracle e disponibilizada já na versão 7.1 do Oracle database, sendo que hoje é a feature de paralelismo mais utilizada no SGBD Oracle. 

Seu principal objetivo é reduzir o tempo de execução de grandes consultas, porém antes de implementá-lo definitivamente devemos testar todas as consultas para garantir que elas vão se beneficiar do paralelismo. 

Para habilitar ou desabilitar o paralelismo podemos alterar uma tabela ou indice informando o grau de paralelismo ou atraves da utilização de hints conforme exemplos abaixo: 

Para habilitar/utilizar o paralelismo: 

-> Nível de objeto

SQL> alter table teste1 parallel (degree 4);
 
Table altered.
 
SQL> alter table teste1 parallel 4;
 
Table altered.

-> Nível de instrução:

SQL> select /*+ PARALLEL(teste1,4,1) */ count(*) from teste1;
 
  COUNT(*)
----------
   1250000

Sintaxe:

select /*+ PARALLEL(table_alias, degree, nodes) */ * from table_name

Para visualizar o paralelismo configurado sobre a tabela/indice:

SQL> select degree from user_tables where table_name='TESTE1';
 
DEGREE
----------
         4

Para desabilitar o paralelismo:

 -> Nível de objeto

SQL> alter table teste1 NOPARALLEL;
 
Table altered.
 
SQL> select degree from user_tables where table_name='TESTE1';
 
DEGREE
----------
         1

-> Nível de instrução:

SQL> select /*+ NOPARALLEL(teste1) */ count(*) from teste1;
 
  COUNT(*)
----------
   1250000

Vamos realizar agora um explain da query para verificar como fica sem e com paralelismo:

SQL> explain plan for
  2  select count(*) from teste1
  3  /
 
Explained.
 
SQL> SELECT * FROM TABLE(dbms_xplan.display);
 
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------
Plan hash value: 3242138447
 
---------------------------------------------------------------------
| Id  | Operation          | Name   | Rows  | Cost (%CPU)| Time     |
---------------------------------------------------------------------
|   0 | SELECT STATEMENT   |        |     1 |   553   (2)| 00:00:07 |
|   1 |  SORT AGGREGATE    |        |     1 |            |          |
|   2 |   TABLE ACCESS FULL| TESTE1 |  1598K|   553   (2)| 00:00:07 |
---------------------------------------------------------------------
 
SQL> explain plan for
  2  select /*+ PARALLEL(teste1,4,1) */ count(*) from teste1
  3  /
 
Explained.
 
SQL> SELECT * FROM TABLE(dbms_xplan.display);
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------
Plan hash value: 721361025
 
--------------------------------------------------------------------------------------------------------
| Id  | Operation              | Name     | Rows  | Cost (%CPU)| Time     |    TQ  |IN-OUT| PQ Distrib |
--------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |          |     1 |   153   (2)| 00:00:02 |        |      |            |
|   1 |  SORT AGGREGATE        |          |     1 |            |          |        |      |            |
|   2 |   PX COORDINATOR       |          |       |            |          |        |      |            |
|   3 |    PX SEND QC (RANDOM) | :TQ10000 |     1 |            |          |  Q1,00 | P->S | QC (RAND)  |
|   4 |     SORT AGGREGATE     |          |     1 |            |          |  Q1,00 | PCWP |            |
|   5 |      PX BLOCK ITERATOR |          |  1598K|   153   (2)| 00:00:02 |  Q1,00 | PCWC |            |
|   6 |       TABLE ACCESS FULL| TESTE1   |  1598K|   153   (2)| 00:00:02 |  Q1,00 | PCWP |            |
--------------------------------------------------------------------------------------------------------

Note que quando executado uma instrução em paralelo temos como evidência as operações PX.

Parallel DML: 

As operações de DML (Data Manipulation Language) INSERT, UPDATE e DELETE também podem ser paralizadas e proporcionar grandes ganhos em tempo/custo, contudo quando a paralelização de DML é acionada o Oracle verifica algumas “regras”/restrições para apontar se a paralelização é válida ou não.

Abaixo podemos ver as regras aplicadas, NOTE que UPDATE e DELETE possuem o mesmo escopo de verificação.

Para UPDATE e DELETE: 

– A paralelização pode ocorrer em tabelas particionadas, mas somente quando várias partições estão envolvidos;

– Não pode ser paralizado o UPDATE e DELETE em uma tabela não particionada ou quando as operações afetam apenas uma única partição.

Para operações de INSERT: 

 – O INSERT padrão utilizando a cláusula VALUES não pode ser paralelizado, apenas pode ser paralelizado as declarações INSERT…SELECT.

Vamos demonstrar um exemplo com e sem paralelismo:

-> INSERT…SELECT sem paralelismo:

SQL> set autotrace traceonly explain;
SQL> insert into teste1 select * from teste1;
 
1250000 rows created.
 
Execution Plan
----------------------------------------------------------
Plan hash value: 110554063
 
-----------------------------------------------------------------------------------
| Id  | Operation                | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------
|   0 | INSERT STATEMENT         |        |  1250K|  4882K|   551   (2)| 00:00:07 |
|   1 |  LOAD TABLE CONVENTIONAL | TESTE1 |       |       |            |          |
|   2 |   TABLE ACCESS FULL      | TESTE1 |  1250K|  4882K|   551   (2)| 00:00:07 |
-----------------------------------------------------------------------------------

-> INSERT…SELECT com paralelismo:

SQL> alter session enable parallel dml;
 
Session altered.
 
SQL> explain plan for
  2  insert /*+ parallel (teste1,4,1) */ into teste1 select * from teste1;
 
Explained.
 
SQL> SELECT * FROM TABLE(dbms_xplan.display);
 
Execution Plan
----------------------------------------------------------
Plan hash value: 1222195891
 
-----------------------------------------------------------------------------------------------------------------
| Id  | Operation               | Name     | Rows  | Bytes | Cost (%CPU)| Time     |    TQ  |IN-OUT| PQ Distrib |
-----------------------------------------------------------------------------------------------------------------
|   0 | INSERT STATEMENT        |          |  1250K|  4882K|    29   (2)| 00:00:02 |        |      |            |
|   1 |  PX COORDINATOR         |          |       |       |            |          |        |      |            |
|   2 |   PX SEND QC (RANDOM)   | :TQ10001 |  1250K|  4882K|    29   (2)| 00:00:02 |  Q1,01 | P->S | QC (RAND)  |
|   3 |    LOAD AS SELECT       | TESTE1   |       |       |            |          |  Q1,01 | PCWP |            |
|   4 |     PX RECEIVE          |          |  1250K|  4882K|    29   (2)| 00:00:02 |  Q1,01 | PCWP |            |
|   5 |      PX SEND ROUND-ROBIN| :TQ10000 |  1250K|  4882K|    29   (2)| 00:00:02 |        | S->P | RND-ROBIN  |
|   6 |       TABLE ACCESS FULL | TESTE1   |  1250K|  4882K|    29   (2)| 00:00:02 |        |      |            |
-----------------------------------------------------------------------------------------------------------------
 
13 rows selected.
 
SQL> commit;
 
Commit complete.
 
SQL> alter session disable parallel dml;
 
Session altered.


Parallel DDL: 

O paralelismo em instruções DDL se aplicam a tabelas e indices, particionadas ou não.

-> Para tabelas: 

CREATE TABLE…AS SELECT
ALTER INDEX…REBUILD PARTITION
ALTER INDEX…SPLIT PARTITION

-> Para indices: 

CREATE INDEX
ALTER INDEX…REBUILD
ALTER INDEX…REBUILD PARTITION
ALTER INDEX…SPLIT PARTITION

Lembrando que tabelas com objetos/campos com LOB não** permitem paralelismo DDL.

Exemplos de paralelismo com DDL:

SQL> explain plan for
  2  create table teste_parallel parallel (degree 4)  as select * from teste1;
 
Explained.
 
SQL> SELECT * FROM TABLE(dbms_xplan.display);
 
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------
Plan hash value: 3992983551
 
----------------------------------------------------------------------------------------------------------------------
| Id  | Operation              | Name           | Rows  | Bytes | Cost (%CPU)| Time     |    TQ  |IN-OUT| PQ Distrib |
----------------------------------------------------------------------------------------------------------------------
|   0 | CREATE TABLE STATEMENT |                |    10M|    38M|  2388   (1)| 00:00:29 |        |      |            |
|   1 |  PX COORDINATOR        |                |       |       |            |          |        |      |            |
|   2 |   PX SEND QC (RANDOM)  | :TQ10000       |    10M|    38M|  1476   (1)| 00:00:18 |  Q1,00 | P->S | QC (RAND)  |
|   3 |    LOAD AS SELECT      | TESTE_PARALLEL |       |       |            |          |  Q1,00 | PCWP |            |
|   4 |     PX BLOCK ITERATOR  |                |    10M|    38M|  1476   (1)| 00:00:18 |  Q1,00 | PCWC |            |
|   5 |      TABLE ACCESS FULL | TESTE1         |    10M|    38M|  1476   (1)| 00:00:18 |  Q1,00 | PCWP |            |
----------------------------------------------------------------------------------------------------------------------

Agora observe se criarmos a tabela sem Paralelismo:

SQL> explain plan for
  2  create table teste_parallel  as select * from teste1;
 
Explained.
 
SQL> SELECT * FROM TABLE(dbms_xplan.display);
 
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------
Plan hash value: 3174501407
 
-----------------------------------------------------------------------------------------
| Id  | Operation              | Name           | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------
|   0 | CREATE TABLE STATEMENT |                |    10M|    38M|  8967   (1)| 00:01:48 |
|   1 |  LOAD AS SELECT        | TESTE_PARALLEL |       |       |            |          |
|   2 |   TABLE ACCESS FULL    | TESTE1         |    10M|    38M|  5320   (1)| 00:01:04 |
-----------------------------------------------------------------------------------------

Vamos ver um indice, com e sem paralelismo:

SQL> explain plan for
  2  create index teste_idx01 on teste1(CD_TESTE) parallel (degree 4);
 
Explained.
 
SQL> SELECT * FROM TABLE(dbms_xplan.display);
 
PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------------------------------------
Plan hash value: 1444741105
 
---------------------------------------------------------------------------------------------------------------------
| Id  | Operation                | Name        | Rows  | Bytes | Cost (%CPU)| Time     |    TQ  |IN-OUT| PQ Distrib |
---------------------------------------------------------------------------------------------------------------------
|   0 | CREATE INDEX STATEMENT   |             |    10M|    38M|  2858   (1)| 00:00:35 |        |      |            |
|   1 |  PX COORDINATOR          |             |       |       |            |          |        |      |            |
|   2 |   PX SEND QC (ORDER)     | :TQ10001    |    10M|    38M|            |          |  Q1,01 | P->S | QC (ORDER) |
|   3 |    INDEX BUILD NON UNIQUE| TESTE_IDX01 |       |       |            |          |  Q1,01 | PCWP |            |
|   4 |     SORT CREATE INDEX    |             |    10M|    38M|            |          |  Q1,01 | PCWP |            |
|   5 |      PX RECEIVE          |             |    10M|    38M|  1476   (1)| 00:00:18 |  Q1,01 | PCWP |            |
|   6 |       PX SEND RANGE      | :TQ10000    |    10M|    38M|  1476   (1)| 00:00:18 |  Q1,00 | P->P | RANGE      |
|   7 |        PX BLOCK ITERATOR |             |    10M|    38M|  1476   (1)| 00:00:18 |  Q1,00 | PCWC |            |
|   8 |         TABLE ACCESS FULL| TESTE1      |    10M|    38M|  1476   (1)| 00:00:18 |  Q1,00 | PCWP |            |
---------------------------------------------------------------------------------------------------------------------

Sem paralelismo:

SQL> explain plan for
  2  create index teste_idx01 on teste1(CD_TESTE);
 
Explained.
 
SQL> SELECT * FROM TABLE(dbms_xplan.display);
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------
Plan hash value: 3409988532
 
--------------------------------------------------------------------------------------
| Id  | Operation              | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------
|   0 | CREATE INDEX STATEMENT |             |    10M|    38M| 10846   (1)| 00:02:11 |
|   1 |  INDEX BUILD NON UNIQUE| TESTE_IDX01 |       |       |            |          |
|   2 |   SORT CREATE INDEX    |             |    10M|    38M|            |          |
|   3 |    TABLE ACCESS FULL   | TESTE1      |    10M|    38M|  5320   (1)| 00:01:04 |
--------------------------------------------------------------------------------------

Referências:

http://docs.oracle.com/cd/B10501_01/server.920/a96524/c20paral.htm http://www.oracle.com/technetwork/issue-archive/2010/o40parallel-092275.html http://www.akadia.com/services/ora_parallel_processing.html#Parallel%20Recovery
Postagem mais recente Postagem mais antiga Página inicial

0 comentários:

Postar um comentário

Translate

# Suporte

# ACE Program

#Oracle

#Oracle
Disclaimer: The views expressed on this blog are my own and do not necessarily reflect the views of Oracle.

#Blog reconhecido

#ARTICULISTA

Marcadores

Postagens populares