AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / coding / Perguntas / 77656799
Accepted
Thorsten Kettner
Thorsten Kettner
Asked: 2023-12-14 06:09:54 +0800 CST2023-12-14 06:09:54 +0800 CST 2023-12-14 06:09:54 +0800 CST

PARALLEL_ENABLE – quando não usar

  • 772

É recomendado declarar funções Oracle PL/SQL como PARALLEL_ENABLEquando elas podem ser paralelizadas, para que o SGBD saiba que pode executar a função em paralelo.

Mas quando uma função é paralelizável? Ou melhor: quando não é?

Vejamos um exemplo:

CREATE OR REPLACE FUNCTION get_country_name(p_country_code VARCHAR2) RETURN VARCHAR2 
  PARALLEL_ENABLE
AS
  PRAGMA UDF;
  v_country_name country.name%TYPE;
BEGIN
  SELECT name INTO v_country_name
  FROM country
  WHERE code = p_country_code;
  RETURN v_country_name;
EXCEPTION WHEN OTHERS THEN
  RETURN NULL;
END;

A função seleciona o nome do país para um determinado código de país, por exemplo, 'França' para 'FR'. Eu fiz UDF, porque vou usá-lo principalmente em consultas SQL, e tornei-o habilitado para paralelo, porque, bem, então funciona melhor em select /*+parallel(4)*/ get_country_name(code) from ...- é isso que significa? Ou o que mais?

E por que posso declarar esta função PARALLEL_ENABLE? O que exatamente o torna paralelizável? Posso simplesmente declarar todas as minhas funções PARALLEL_ENABLE? Então eu deveria, não deveria? Ou existem circunstâncias que impediriam isso? O que impediria uma função de ser paralelizável?

oracle
  • 2 2 respostas
  • 40 Views

2 respostas

  • Voted
  1. Best Answer
    Paul W
    2023-12-14T08:05:29+08:002023-12-14T08:05:29+08:00

    PARALLEL_ENABLEé um tanto misterioso. A documentação da Oracle não é muito clara. É certo que você não precisa disso na consulta paralela (PQ, paralelização de SELECTblocos) - os escravos paralelos executarão alegremente suas funções escalares na SELECTcláusula sem serem marcados como PARALLEL_ENABLE.

    Um lugar onde definitivamente faz diferença é com DML paralelo (pdml) ao usar funções não puras . De acordo com os documentos:

    Habilita a função para execução paralela, tornando-a segura para uso em sessões simultâneas de avaliações DML paralelas.

    Na verdade, isso só é necessário quando a função não é pura e nem quando é PQ regular. Aqui está uma demonstração, usando arbitrariamente uma grande tabela que chamei de "instantâneo".

    Isso executa a chamada de função em série e desativa efetivamente o funcionamento do pdml:

    CREATE OR REPLACE FUNCTION myname(in_value IN integer)
      RETURN number 
    AS  
      PRAGMA UDF;
    BEGIN
      RETURN SYS_CONTEXT('USERENV','SID'); -- makes it non-pure
    END;
      
    create table tmp1 (col1 integer)  ;
    
    alter session enable parallel dml;
    
    insert /*+ append parallel(x,32) */ into tmp1 x 
    select /*+ parallel(32) full(s) */ myname(snapshot_id) from snapshot s
    

    Plano de execução:

    ----------------------------------------------------------------------------------------------------------------------------
    | Id  | Operation                          | Name     | Rows  | Bytes | Cost (%CPU)| Time     |    TQ  |IN-OUT| PQ Distrib |
    ----------------------------------------------------------------------------------------------------------------------------
    |   0 | INSERT STATEMENT                   |          |   344M|  2302M| 10381   (1)| 00:00:01 |        |      |            |
    |   1 |  LOAD AS SELECT                    | TMP1     |       |       |            |          |        |      |            |
    |   2 |   PX COORDINATOR                   |          |       |       |            |          |        |      |            |
    |   3 |    PX SEND QC (RANDOM)             | :TQ10000 |   344M|  2302M| 10381   (1)| 00:00:01 |  Q1,00 | P->S | QC (RAND)  |
    |   4 |     OPTIMIZER STATISTICS GATHERING |          |   344M|  2302M| 10381   (1)| 00:00:01 |  Q1,00 | PCWC |            |
    |   5 |      PX BLOCK ITERATOR             |          |   344M|  2302M| 10381   (1)| 00:00:01 |  Q1,00 | PCWC |            |
    |   6 |       TABLE ACCESS FULL            | SNAPSHOT |   344M|  2302M| 10381   (1)| 00:00:01 |  Q1,00 | PCWP |            |
    ----------------------------------------------------------------------------------------------------------------------------
     
    Hint Report (identified by operation id / Query Block Name / Object Alias):
    Total hints for statement: 1 (U - Unused (1))
    ---------------------------------------------------------------------------
     
       0 -  INS$1 / X@INS$1
             U -  parallel(x,8)
     
    Note
    -----
       - Degree of Parallelism is 32 because of hint
       - PDML disabled because function is not pure and not declared parallel enabled
    

    Como você pode ver, a LOAD AS SELECToperação vem acima/depois PX COORDINATOR, portanto não há PDML. A etapa de inserção real é serializada. Os comentários do plano até nos dão um exemplo do porquê. Claro que isso faz sentido: dependendo de qual escravo PX o executa, o resultado será diferente (já que estou retornando o SID do processo em execução). A Oracle não quer que obtenhamos resultados diferentes dependendo se o PX está envolvido ou não ou como as linhas são distribuídas, mas isso causaria isso.

    Então, temos que jurar em nossos túmulos que é isso que realmente queremos. Agora adicione PARALLEL_ENABLE:

    CREATE OR REPLACE FUNCTION myname(in_value IN integer)
      RETURN number PARALLEL_ENABLE
    AS  
      PRAGMA UDF;
    BEGIN
      RETURN SYS_CONTEXT('USERENV','SID');
    END;
    
    insert /*+ append parallel(x,8) */ into tmp1 x select /*+ parallel(32) full(s) */ myname(snapshot_id) from snapshot s
    

    Plano de execução:

    ----------------------------------------------------------------------------------------------------------------------------
    | Id  | Operation                          | Name     | Rows  | Bytes | Cost (%CPU)| Time     |    TQ  |IN-OUT| PQ Distrib |
    ----------------------------------------------------------------------------------------------------------------------------
    |   0 | INSERT STATEMENT                   |          |   344M|  2302M| 10381   (1)| 00:00:01 |        |      |            |
    |   1 |  PX COORDINATOR                    |          |       |       |            |          |        |      |            |
    |   2 |   PX SEND QC (RANDOM)              | :TQ10000 |   344M|  2302M| 10381   (1)| 00:00:01 |  Q1,00 | P->S | QC (RAND)  |
    |   3 |    LOAD AS SELECT (HYBRID TSM/HWMB)| TMP1     |       |       |            |          |  Q1,00 | PCWP |            |
    |   4 |     OPTIMIZER STATISTICS GATHERING |          |   344M|  2302M| 10381   (1)| 00:00:01 |  Q1,00 | PCWP |            |
    |   5 |      PX BLOCK ITERATOR             |          |   344M|  2302M| 10381   (1)| 00:00:01 |  Q1,00 | PCWC |            |
    |   6 |       TABLE ACCESS FULL            | SNAPSHOT |   344M|  2302M| 10381   (1)| 00:00:01 |  Q1,00 | PCWP |            |
    ----------------------------------------------------------------------------------------------------------------------------
     
    Note
    -----
       - Degree of Parallelism is 32 because of hint
    

    Agora LOAD AS SELECTvem abaixo/antes PX COORDINATOR, então estamos em modo PDML completo aqui e essa inserção será muito mais rápida. A adição PARALLEL_ENABLEdessa função escalar tornou possível usá-la em uma operação PDML.

    Se a função fosse pure , a PARALLEL_ENABLEcláusula não seria necessária. O PDML funcionará perfeitamente sem ele, porque a Oracle sabe que o resultado não mudará, independentemente de como as linhas são distribuídas:

    CREATE OR REPLACE FUNCTION myname(in_value IN integer)
      RETURN number
    AS  
      PRAGMA UDF;
    BEGIN
      RETURN in_value*100;
    END;
    

    Plano:

    ----------------------------------------------------------------------------------------------------------------------------
    | Id  | Operation                          | Name     | Rows  | Bytes | Cost (%CPU)| Time     |    TQ  |IN-OUT| PQ Distrib |
    ----------------------------------------------------------------------------------------------------------------------------
    |   0 | INSERT STATEMENT                   |          |   344M|  2302M| 10381   (1)| 00:00:01 |        |      |            |
    |   1 |  PX COORDINATOR                    |          |       |       |            |          |        |      |            |
    |   2 |   PX SEND QC (RANDOM)              | :TQ10000 |   344M|  2302M| 10381   (1)| 00:00:01 |  Q1,00 | P->S | QC (RAND)  |
    |   3 |    LOAD AS SELECT (HYBRID TSM/HWMB)| TMP1     |       |       |            |          |  Q1,00 | PCWP |            |
    |   4 |     OPTIMIZER STATISTICS GATHERING |          |   344M|  2302M| 10381   (1)| 00:00:01 |  Q1,00 | PCWP |            |
    |   5 |      PX BLOCK ITERATOR             |          |   344M|  2302M| 10381   (1)| 00:00:01 |  Q1,00 | PCWC |            |
    |   6 |       TABLE ACCESS FULL            | SNAPSHOT |   344M|  2302M| 10381   (1)| 00:00:01 |  Q1,00 | PCWP |            |
    ----------------------------------------------------------------------------------------------------------------------------
     
    Note
    -----
       - Degree of Parallelism is 32 because of hint
    

    Ainda no modo PDML, mas sem PARALLEL_ENABLE.

    Existem outros usos para isso. Os documentos discutem isso em conexão com funções em pipeline, especialmente com cursores de referência, mas nunca vi isso funcionar definitivamente. Eu o adiciono rotineiramente às minhas funções de pipeline, mas minha execução sempre mostra saída serializada que é então distribuída para o primeiro conjunto de escravos PX. Nunca vi a saída em si paralelizada.

    Talvez alguém possa colocar sua experiência aqui e tenha conseguido fazê-lo funcionar com funções de tabela em pipeline .

    • 4
  2. Jon Heller
    2023-12-14T13:53:07+08:002023-12-14T13:53:07+08:00

    PARALLEL_ENABLE costumava ser mais importante e era necessário para qualquer tipo de operação paralela. Os efeitos atuais são muito menores e são bem descritos pela resposta de Paulo.

    De acordo com a Referência da Linguagem PL/SQL do Banco de Dados 11.2 , PARALLEL_ENABLEera necessário para permitir que a função fosse executada em paralelo:

    cláusula_enable_paralela

    Indica que a função pode ser executada a partir de um servidor de execução paralela de uma operação de consulta paralela. A função não deve usar o estado da sessão, como variáveis ​​de pacote, pois essas variáveis ​​não são necessariamente compartilhadas entre os servidores de execução paralela.

    A Referência da Linguagem PL/SQL do Banco de Dados 12.2 agora explica que a cláusula se aplica principalmente a operações DML. Acho que a última frase da citação abaixo é um bug de documentação; o autor adicionou a primeira frase limitando o escopo desta cláusula, mas esqueceu de modificar a frase original que implicava que a cláusula se aplica a todas as operações paralelas.

    Cláusula PARALLEL_ENABLE

    Habilita a função para execução paralela, tornando-a segura para uso em sessões escravas de avaliações DML paralelas.

    Indica que a função pode ser executada a partir de um servidor de execução paralela de uma operação de consulta paralela.

    Não tenho uma instância 11g para teste, mas acho que me lembro de ter que adicionar PARALLEL_ENABLEmuitas funções, mesmo que não houvesse DML envolvido. E com base em meus testes, sua função usada em uma consulta deve ser executada com a mesma rapidez, com ou sem PARALLEL_ENABLE.

    • 1

relate perguntas

  • Oracle - Execuções Restantes

  • Servidor ODBC Informix: Erro ao extrair o nome do mês da data

  • Oracle sqlldr: as restrições não são reativadas após o término do carregamento do lote

  • importando um arquivo csv para o banco de dados oracle

  • Buscando registros de horas anteriores no Oracle

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    destaque o código em HTML usando <font color="#xxx">

    • 2 respostas
  • Marko Smith

    Por que a resolução de sobrecarga prefere std::nullptr_t a uma classe ao passar {}?

    • 1 respostas
  • Marko Smith

    Você pode usar uma lista de inicialização com chaves como argumento de modelo (padrão)?

    • 2 respostas
  • Marko Smith

    Por que as compreensões de lista criam uma função internamente?

    • 1 respostas
  • Marko Smith

    Estou tentando fazer o jogo pacman usando apenas o módulo Turtle Random e Math

    • 1 respostas
  • Marko Smith

    java.lang.NoSuchMethodError: 'void org.openqa.selenium.remote.http.ClientConfig.<init>(java.net.URI, java.time.Duration, java.time.Duratio

    • 3 respostas
  • Marko Smith

    Por que 'char -> int' é promoção, mas 'char -> short' é conversão (mas não promoção)?

    • 4 respostas
  • Marko Smith

    Por que o construtor de uma variável global não é chamado em uma biblioteca?

    • 1 respostas
  • Marko Smith

    Comportamento inconsistente de std::common_reference_with em tuplas. Qual é correto?

    • 1 respostas
  • Marko Smith

    Somente operações bit a bit para std::byte em C++ 17?

    • 1 respostas
  • Martin Hope
    fbrereto Por que a resolução de sobrecarga prefere std::nullptr_t a uma classe ao passar {}? 2023-12-21 00:31:04 +0800 CST
  • Martin Hope
    比尔盖子 Você pode usar uma lista de inicialização com chaves como argumento de modelo (padrão)? 2023-12-17 10:02:06 +0800 CST
  • Martin Hope
    Amir reza Riahi Por que as compreensões de lista criam uma função internamente? 2023-11-16 20:53:19 +0800 CST
  • Martin Hope
    Michael A formato fmt %H:%M:%S sem decimais 2023-11-11 01:13:05 +0800 CST
  • Martin Hope
    God I Hate Python std::views::filter do C++20 não filtrando a visualização corretamente 2023-08-27 18:40:35 +0800 CST
  • Martin Hope
    LiDa Cute Por que 'char -> int' é promoção, mas 'char -> short' é conversão (mas não promoção)? 2023-08-24 20:46:59 +0800 CST
  • Martin Hope
    jabaa Por que o construtor de uma variável global não é chamado em uma biblioteca? 2023-08-18 07:15:20 +0800 CST
  • Martin Hope
    Panagiotis Syskakis Comportamento inconsistente de std::common_reference_with em tuplas. Qual é correto? 2023-08-17 21:24:06 +0800 CST
  • Martin Hope
    Alex Guteniev Por que os compiladores perdem a vetorização aqui? 2023-08-17 18:58:07 +0800 CST
  • Martin Hope
    wimalopaan Somente operações bit a bit para std::byte em C++ 17? 2023-08-17 17:13:58 +0800 CST

Hot tag

python javascript c++ c# java typescript sql reactjs html

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve