Método de otimização de desempenho de procedimento armazenado Oracle PLSQL

Método de otimização de desempenho de procedimento armazenado Oracle PLSQL

1. Causas comuns que afetam o desempenho

1. Tente usar procedimentos armazenados e evite usar blocos anônimos PL/SQL

Após a criação do procedimento armazenado, o Oracle realizará a análise sintática do mesmo e o armazenará no banco de dados em forma compilada.Quando o cliente o chama, ele só precisa enviar uma instrução de chamada, o que evita que o bloco anônimo transmita uma grande quantidade de código-fonte na Internet e reduz o custo da rede. A carga de comunicação e, como só é compilado uma vez no momento da criação, o desempenho da execução do programa é melhorado.

2. Escreva uma instrução SQL compartilhada

Quando o Oracle executa uma instrução SQL, após a primeira análise, ele colocará a instrução SQL no pool compartilhado localizado na área global do sistema SGA.Esta área de memória pode ser compartilhada por todos os usuários do banco de dados, portanto, ao executar uma instrução SQL, por exemplo, quando um cursor em uma instrução PL/SQL executa uma instrução SQL, se o Oracle detectar que é igual a uma instrução que foi executada antes, ele usará a instrução analisada e o caminho de execução ideal.

Quando o Oracle executa uma instrução SQL, ele sempre pesquisará primeiro a mesma instrução SQL na área de memória compartilhada.No entanto, como o Oracle armazena em cache apenas tabelas simples, não é adequado para consultas de conexão de várias tabelas.

SELECIONE * DO EMP;

SELECIONE * do EMP;

Selecione * em Emp;

SELECIONE * DO EMP;

Para evitar esse tipo de instrução SQL, ao escrever instruções SQL, você deve prestar atenção ao uso de convenções de maiúsculas e minúsculas consistentes, palavras-chave, palavras reservadas em maiúsculas e identificadores declarados pelo usuário em minúsculas. por essas convenções, você pode processar A instrução é consistente com a do pool compartilhado, o que ajuda a melhorar o desempenho de execução.

3. Use BINARY_INTEGER e PLS_INTEGER para declarar inteiros

Ao declarar tipos de variáveis ​​na programação PLSQL, você deve sempre usar BINARY_INTEGER e PLS_INTEGER para evitar depender muito do tipo numérico, pois o primeiro fornece desempenho mais rápido.

4. Use o prompt de compilação NOCOPY ao passar parâmetros de dados grandes no processo

Ao criar um procedimento ou função, o modo IN sempre passa um ponteiro, enquanto OUT e IN OUT passam uma cópia do valor, também conhecido como passagem por valor. Quando a passagem de parâmetros de grande capacidade está envolvida, o desempenho será seriamente reduzido. Neste momento, você deve considerar o uso da dica de compilação NOCOPY para passar parâmetros por referência. Quanto maior o tamanho do parâmetro, mais óbvio será o efeito. Por exemplo, suponha que um procedimento tenha um
tipo IN OUT Os parâmetros são passados ​​por valor por padrão. O exemplo a seguir demonstra chamar esse processo várias vezes e passar um parâmetro de tabela de índice grande. Se NOCOPY não for usado, o desempenho será seriamente reduzido.

Use NOCOPY para melhorar o desempenho

declare
type test_tb1 is table of pls_integer index by pls_integer;  --定义索引表类型
test_tb1 test_tb1_type;   --定义索引表类型的变量
--定义内嵌子程序,在IN OUT 参数中使用NOCOPY提示来按引用传递
procedure test (arg_cnt in pls_integer,arg_tb1 in out nocopy test_tb1_type)
is
begin
for cnt_test in test_tb1.first .. arg_tb1.last --依循环索引表
loop
arg_tb1 (cnt_test):=arg_tb1 (cnt_test) + arg_cnt;
end loop;	--为形式参数表赋值
end;
begin
for cnt in 0 .. 10000
loop
test_tb1 (cnt) := cnt;
end loop;
for cnt in 0 .. 10000
loop
test (cnt,test_tb1);
end loop;
end;

5. Use o retorno para obter o valor de retorno

Ao usar instruções DML para processar dados de linha de objeto, se desejar obter o valor de retorno da linha, você deve sempre usar a cláusula de retorno para reduzir o número de execuções SQL e melhorar a eficiência da execução:

inserir em... valor (...) retornando col1 em: col1;
atualizar... definir... retornando col1 em: col1;
excluir... retornando col1 em: col1;
Usando o retorno, você pode não apenas retornar dados de múltiplas colunas, mas também retornar dados e salvar para arrays e outros tipos de dados. Médio:
retornando col1, col2 em :col1, :col2;
retornando col1 em :col1_array;

6. Evite usar instruções SQL dinâmicas

Embora as instruções SQL dinâmicas forneçam conveniência de programação, o uso excessivo de instruções SQL dinâmicas reduzirá seriamente o desempenho dos aplicativos PLSQL. Portanto, se necessário, você deve sempre considerar o uso de instruções SQL estáticas. Se você tiver que usar instruções SQL dinâmicas, você deve sempre optar por usar instruções SQL dinâmicas locais, ou seja, executar imediatamente ou abrir para em vez de usar dbms_sql, porque dbms_sql não é apenas mais complicado de escrever código, mas também tem desempenho pior do que instruções SQL dinâmicas locais.

7. Tente usar processamento em lote em massa

Se a operação envolver uma grande quantidade de dados, você poderá melhorar o desempenho processando uma grande quantidade de dados de uma só vez. Por exemplo, você pode colocar os dados em tabelas de índice, tabelas aninhadas e matrizes de comprimento variável e usar instruções de processamento em lote como coleta total ou em massa, processando grandes quantidades de dados de uma só vez e melhorando o desempenho.

Use a instrução bulk collect into para inserir todos os dados da tabela emp nas variáveis ​​da tabela de índice de uma só vez.Quando a quantidade de dados é particularmente grande, isso pode melhorar significativamente o desempenho.

Obtenha todos os dados de uma só vez usando processamento em lote

declare
type emp_tb1 is table of emp%ROWTYPE index by pls_integer; --定义索引表类型
        emp_tb1	emp_tb1_type;
cursor	emp_cur
is
select * from emp;
begin
open emp_cur;
fetch emp_cur
bulk collect into emp_tb1;
close emp_cur;
end;

Ao usar a cláusula bulk collect into, todos os dados do cursor são extraídos para variáveis ​​da tabela de índice de uma só vez, o que melhora o desempenho de execução do programa e economiza a quantidade de gravação de código. Portanto, sempre que possível, o processamento em lote deve ser utilizado para completar o processamento dos dados.

2. Use o pacote DBMS_PROFILER

1.Instale o pacote DBMS_PROFILER

Antes de usar DBMS_PROFILER, você deve entrar no sistema de banco de dados como administrador para instalá-lo.
conn system/manager as sysdba;
desc dbms_profiler;
Se o comando desc informar que o pacote dbms_profiler não existe, você precisará usar o seguinte comando para instalá-lo:
sql>@?/rdbms/admin/profload.sql
Execute desc dbms_profiler novamente , você pode ver este pacote As informações da sub-rotina contidas, existem duas funções principais usadas:
start_profiler inicia o criador de perfil
stop_profiler interrompe o perfil

2. Configure o esquema do criador de perfil

Crie um usuário para armazenar informações de rastreamento e sinônimos para tabelas relacionadas ao criador de perfil:

criar perfil de usuário identificado por 123456;
conceder conexão, recurso ao criador de perfil;
crie sinônimo público plsql_profiler_runs para profiler.plsql_profiler_runs;
crie sinônimo público plsql_profiler_units para profiler.plsql_profiler_units;
crie um sinônimo público plsql_profiler_data para profiler.plsql_profiler_data;
crie um sinônimo público plsql_profiler_runnumber para profiler.plsql_profiler_runnumber;

3. Configure a tabela do criador de perfil

criador de perfil de conexão/123456

@?/rdbms/admin/proftab.sql

conceder seleção em plsql_profile_runnumber para público;
conceder seleção, inserção, atualização, exclusão em plsql_profiler_data para público;
conceder seleção, inserção, atualização, exclusão em plsql_profiler_units para público;
conceder seleção, inserção, atualização, exclusão em plsql_profiler_runs para público;
plsql_profile_runnumber criador de perfil salvo O informações de execução
plsql_profiler_data salva as informações do criador de perfil de cada unidade
plsql_profiler_units salva os dados detalhados de cada unidade
plsql_profiler_runs é usado para gerar a sequência do número de execução exclusivo do criador de perfil.

4. Execute o profiler para obter informações de configuração

Depois de criar o processo, você pode usar o profiler para instrumentar o código do programa.
Crie um processo a ser testado

create table pro_tst_table (a int);
create or replace procedure sp_test
as
begin
for i in 1 .. 10000
loop
insert into pro_tst_table values(i);
end loop;
commit;
end;

Use dbms_profiler para testar pacotes

declare
v_run_number	integer;
v_temp1	integer;
begin
--启动profiler
sys.DBMS_PROFILER.start_profiler(run_number => v_run_number);
--显示当前跟踪的运行序号(后面查询要用)
dbms_output.put_line('run_number:'||v_run_number);
--运行要跟踪的PLSQL
sp_test;
--停止profiler
sys.DBMS_PROFILER.stop_profiler;
end;

5. Consulte o criador de perfil para obter resultados

Para usar instruções SQL para consultar as informações desta execução, você pode primeiro consultar plsql_profiler_runs para obter as informações básicas desta execução:
select runid, run_owner, run_date, run_total_time from plsql_profiler_runs;
O autor executou o código duas vezes, portanto, há dois registros runid , ID O valor é gerado por meio do número de série, e o valor máximo do ID indica a execução mais recente.
RUN_TOTAL_TIME indica o tempo de execução. Você pode ver que o tempo das duas execuções é significativamente diferente. As
informações da unidade deste perfil podem ser obtido consultando a tabela plsql_profiler_units.
Ao consultar a tabela plsql_profiler_data, você pode obter informações estatísticas para cada linha do procedimento armazenado executado com base no número da linha e no número da unidade.

3. Use o pacote DBMS_TRACE

Por exemplo, se você vir a ordem de execução das sub-rotinas, poderá usar o pacote DBMS_TRACE. O uso deste pacote é semelhante ao uso do DBMS_PROFILER. Uma grande diferença é que dbms_trace pode definir os eventos que precisam ser rastreados: chamadas, exceções, SQL e até mesmo os possíveis eventos de cada código PLSQL. Com a ajuda dessas informações, as anormalidades no processo do programa em segundo plano podem ser localizadas muito rapidamente.

Existem duas funções no pacote:

set_plsql_trace: permite a coleta de estatísticas de rastreamento.

clear_plsql_trace: interrompe a coleta de estatísticas de rastreamento

1. Configure e use DBMS_TRACE

Antes de usá-lo, você precisa configurar as tabelas de dados usadas por dbms_trace e permitir que todos os usuários gravem dados nessas tabelas.

conn sistema/gerente como sysdba

@?/rdbms/admin/tracetab.sql

O script cria duas tabelas e uma sequência

Tabela plsql_trace_runs: usada para registrar cada informação de rastreamento.

Tabela plsql_trace_events: usada para registrar dados detalhados de todos os rastreamentos

Sequência plsql_trace_runnumber: uma sequência usada para gerar números de execução exclusivos.

2. Depois de criar com êxito as tabelas necessárias, você precisa criar sinônimos para as tabelas correspondentes e atribuir permissões acessíveis a elas para que os usuários com função pública possam operar nas tabelas correspondentes.

crie ou substitua o sinônimo público plsql_trace_runs por sys.plsql_trace_runs;

crie ou substitua o sinônimo público plsql_trace_events por sys.plsql_trace_events;

crie ou substitua o sinônimo público plsql_trace_runnumber por sys.plsql_trace_runnumber;

conceder seleção, inserção, atualização, exclusão em plsql_trace_events para público;

conceder seleção, inserção, atualização, exclusão em plsql_trace_runs para público;

conceder seleção em plsql_trace_runnumber para público;

Criar programa de teste dbms_trace

create or replace procedure do_something (p_times in number)
as
1_dummy	number;
begin
for i in 1 .. p_times
loop
select 1_dummy + 1 into 1_dummy from dual;
end loop;
end;

Usando o programa de rastreamento dbms_trace

declare
1_result binary_integer;
begin
--跟踪所有的调用
dbms_trace.set_plsql_trace(dbms_trace.trace_all_calls);
do_something(100);
--停止PLSQL跟踪
dbms_trace.clear_plsql_trace;
--跟踪所有的sql语句
dbms_trace.set_plsql_trace(dbms_trace.trace_all_sql);
do_something(100);
--停止跟踪
dbms_trace.clear_plsql_trace;
--跟踪所有行数据
dbms_trace.set_plsql_trace(dbms_trace.trace_all_lines);
do_something(100);
dbms_trace.clear_plsql_trace;
end;

Para cada chamada, set_plsql_trace é usado primeiro para iniciar o processo de rastreamento. O parâmetro DBMS_TRACE_trace_all_calls deste processo é uma constante especificada para rastrear a chamada ou valor de retorno.

A especificação do pacote DBMS_TRACE contém uma lista e uma explicação detalhada das constantes disponíveis para set_plsql_trace.

Obtenha informações sobre cada rastreamento consultando a tabela plsql_trace_runs.

4. Habilidades de otimização de desempenho PLSQL

Quando o banco de dados Oracle executa uma instrução SQL, o otimizador da Oracle determinará o caminho de execução da instrução SQL de acordo com certas regras para garantir que a instrução SQL possa ser executada com desempenho ideal.Para executar a instrução SQL no sistema de banco de dados Oracle, A Oracle pode precisar implementar vários Cada uma dessas etapas pode ser a recuperação física de linhas de dados do banco de dados ou a preparação das linhas de dados de alguma forma para serem usadas pelo usuário que escreve a instrução SQL. A combinação dessas etapas usadas pela Oracle para executar a instrução é chamada de plano de execução.

O Oracle passa por 4 etapas ao executar uma instrução SQL:

Analisar instruções SQL: consulte principalmente as mesmas instruções SQL no pool compartilhado para verificar a segurança e a sintaxe e semântica SQL.

Criação de planos de execução e execução: incluindo criação de planos de execução para instruções SQL e aquisição real de dados de tabelas.

Exibir o conjunto de resultados: executa toda a classificação, conversão e reformatação necessária dos dados do campo.

Converter dados de campo: reformate e converta campos que foram convertidos por meio de funções integradas.

Verifique o plano de execução da instrução sql. Por exemplo, algumas ferramentas de terceiros precisam executar primeiro o script utlxplan.sql para criar a tabela explica_plan.

@?/rdbms/admin/utlxplan.sql

definir autotrace em explicar: execute sql e exiba apenas o plano de execução

definir autotrace nas estatísticas: executar sql e exibir apenas estatísticas de execução

ativar o autotrace: executa o sql e exibe o plano de execução e informações estatísticas, sem resultados de execução

set autotrace traceonly: exibe apenas o plano de execução e informações estatísticas, sem resultados de execução

desativar o rastreamento automático: desativa o plano de exibição de rastreamento e estatísticas

definir autotrace em explicar

formato de nome de coluna a20;

selecione empno,ename de emp onde empno=7369;

5. Entenda o plano de execução

1. Varredura completa da tabela: Este método irá ler todos os registros da tabela e ler cada bloco de dados sequencialmente até a marca final.Para uma tabela de dados grande, usar uma varredura completa da tabela reduzirá o desempenho, mas algumas vezes, por exemplo, quando o os resultados da consulta representam uma proporção relativamente alta do volume de dados de toda a tabela, a varredura completa da tabela é um método melhor do que a seleção do índice.

2. Obter o valor através do ROWID: O rowid da linha indica o arquivo de dados onde a linha está localizada, o bloco de dados e a posição da linha no bloco. Portanto, acessar os dados através do rowid pode localizar rapidamente os dados de destino, que é uma única linha acessada pelo Oracle. A maneira mais rápida de obter dados.

3. Varredura de índice: primeiro encontre o valor rowid do objeto por meio do índice e, em seguida, encontre os dados específicos diretamente da tabela por meio do valor rowid, o que pode melhorar muito a eficiência da pesquisa.

6. Ordem da tabela para consulta de junção

Por padrão, o otimizador usará o método de otimização all_rows, que é o otimizador CBO baseado em custos para gerar um plano de execução. O método CBO gerará um plano de execução baseado em informações estatísticas.

As informações estatísticas fornecem o tamanho da tabela, o número de linhas, o comprimento de cada linha e outras informações. Essas informações estatísticas não estão inicialmente disponíveis na biblioteca. Elas foram descobertas após fazer uma análise. Muitas vezes informações estatísticas expiradas causarão o otimizador comete um erro no plano de implementação, portanto, essas informações devem ser atualizadas em tempo hábil.

No modo CBO, ao realizar uma consulta de junção em múltiplas tabelas, o analisador oracle processará os nomes das tabelas na cláusula from na ordem da direita para a esquerda. Por exemplo:

selecione a.empno, a.ename, c.deptno, c.dname, a.log_action de emp_log a,emp b,dept c

Durante a execução, o Oracle primeiro consultará a tabela dept e usará as linhas consultadas na tabela dept como fonte de dados para se conectar serialmente à tabela emp para continuar a execução.Portanto, a tabela dept também é chamada de tabela base ou tabela de driver . Porque a ordem das conexões tem um grande impacto na eficiência da consulta. Portanto, ao processar conexões de várias tabelas, você deve escolher uma tabela com menos registros como tabela base, e o Oracle usará classificação e mesclagem para conectar. Por exemplo, primeiro verifique a tabela dept, depois classifique a tabela dept, depois verifique a tabela emp e, finalmente, mescle todos os registros recuperados com os registros da primeira tabela.

Se houver mais de 3 tabelas conectadas à consulta, será necessário selecionar a crosstab como tabela base. A tabela cruzada refere-se à tabela que é referenciada por outras tabelas. Como emp_log é uma tabela cruzada entre as tabelas dept e emp, ela contém o conteúdo de dept e emp.

selecione a.empno, a.ename, c.deptno, c.dname, a.log_action de emp b,dept c,emp_log a;

7. Especifique a sequência das condições onde

Ao consultar uma tabela, a ordem das condições na cláusula where geralmente afeta o desempenho da execução. Por defeito,o Oracle analisa cláusulas where por ordem ascendente.Portanto,ao processar consultas multi-tabelas,as ligações entre tabelas devem ser escritas antes de outras condições where,mas as condições para filtrar registos de dados devem ser escritas antes de where no final da cláusula para que a conexão possa ser processada após a filtragem dos dados, o que pode melhorar o desempenho da instrução SQL.

Evite usar o símbolo *

8. Use a função de decodificação

Por exemplo, para contar o número e o resumo salarial dos funcionários com departamento número 20 e departamento número 30 na tabela emp, se você não usar decodificação, deverá usar duas instruções SQL.

selecione count( ),SUM(sal) de emp onde deptno=20;
união
selecione contagem(
),SUM(sal) de emp onde deptno=30;

Duas varreduras completas da tabela foram realizadas acima

Através da instrução decode, os mesmos resultados podem ser obtidos em uma consulta SQL e as duas linhas de resultados são exibidas como uma única linha.

selecione contagem (decodificar (deptno, 20, 'X', NULL)) dept20_count,
contagem (decodificar (deptno, 30, 'X', NULL)) dept30_count,
SUM (decodificar (deptno, 20, sal, NULL)) dept20_sal,
soma (decodificar (deptno,30,sal,NULL)) dept30_sal de emp;

Apenas uma varredura completa da tabela foi realizada acima

Ao usar a função decodificar de maneira flexível, você pode obter muitos resultados inesperados, como usar a função decodificar em uma cláusula group by ou order by ou aninhar outro bloco de decodificação dentro de um bloco de decodificação.

9. Use onde em vez de ter

Tanto a cláusula where quanto a cláusula holding podem filtrar dados, mas a cláusula where não pode usar funções agregadas, como contagem max min avg sum e outras funções.

exemplo:

selecione empno,deptno,sum(sal) do grupo emp por empno,deptno
tendo sum(sal) > 1000 e deptno em (20,30);

Na cláusula tendo, são filtrados os registros com números de departamento 20 ou 30. Na verdade, isso fará com que a consulta recupere os registros dos funcionários de todos os departamentos, realize cálculos de agrupamento e, por fim, filtre os registros dos departamentos 20 e 30 com base nos resultados do agrupamento. Isso é muito ineficiente. Um bom algoritmo é primeiro usar a cláusula where para recuperar os registros com números de departamento 20 e 30 e depois filtrá-los.

selecione empno,deptno,soma(sal) de emp onde deptno em (20,30)
grupo por empno,deptno tendo soma (sal) > 1000;

10. Use UNION em vez de OR

Se as duas colunas a serem ORed forem colunas de índice, você poderá considerar o uso de união para melhorar o desempenho.

Exemplo: por exemplo, na tabela emp,as colunas de índice são criadas para empno e ename.Quando você precisa executar uma consulta de operação OR entre empno e ename,você pode considerar alterar essas duas consultas para união para melhorar o desempenho.

selecione empno,ename,job,sal de emp onde empno > 7500 OU ename LIKE 'S%';

11. Use UNIÃO

selecione empno, ename, job, sal de emp onde empno > 7500
UNION
selecione empno, ename, job, sal de emp onde ename LIKE 'S%';

Mas este método garante que ambas as colunas sejam colunas de índice.

Se você insistir em usar a instrução OR, lembre-se de escrever a coluna de índice com o menor número possível de registros retornados na frente, para obter melhor desempenho. Por exemplo, empno > 7500 retorna menos registros do que a consulta para ename, portanto, na instrução OR, colocá-lo na frente proporcionará melhor desempenho. Outra sugestão é considerar o uso de IN ao realizar cálculos OR em um único valor de campo

Por exemplo o seguinte

selecione empno,ename,job,sal de emp onde deptno=20 OU deptno=30;

12. O uso existe em vez de IN

Por exemplo, para consultar a lista de todos os funcionários localizados em Chicago, considere usar IN

selecione * de emp onde deptno IN (
selecione deptno de dept onde loc='CHICAGO');

substituir com

selecione * de emp onde existe (
selecione deptno de dept onde loc='CHICAGO');

A mesma página de substituição ocorre entre not in e not exist. A cláusula not in executará uma classificação e mesclagem interna. Na verdade, ela executa uma varredura completa da tabela na subconsulta, portanto a eficiência é baixa. Quando você precisar uso No caso de NOT IN, Yingai sempre considera alterá-lo para uma conexão externa ou NOT EXISTS.

selecione * de emp onde deptno NOT IN (
selecione deptno de dept onde loc='CHICAGO');

Para melhorar o desempenho, você pode usar a consulta de junção

selecione a.* de emp a,dept b onde a.deptno=b.deptno e b.loc <> 'CHICAGO';

mais eficiente

selecione a.* de emp a onde NÃO EXISTE (
selecione 1 de dept b onde a.deptno =b.deptno e loc='CHICAGO');

13. Evite instruções de controle de processo PL/SQL ineficientes

PLSQL usa o método de cálculo de caminho curto ao processar valores de expressões lógicas.

declare
v_sal	number:=&sal;
v_job	varchar2(20):=&job;
begin
if (v_sal > 5000 ) OR (v_job = '销售')
then
dbms_output.put_line('符合匹配的OR条件');
end if;
end;

Primeiro, a primeira condição é julgada. Se v_sal for maior que 5000, a condição v_job não será julgada. O uso flexível deste método de cálculo de curto-circuito pode melhorar o desempenho. Você deve sempre colocar as instruções de julgamento de custo mais baixo primeiro, para que, quando o julgamento anterior falhar, as instruções subsequentes de custo mais alto não sejam executadas, o que pode melhorar o desempenho dos aplicativos PL/SQL.

Por exemplo, para o operador lógico e, o resultado será verdadeiro somente se as operações à esquerda e à direita forem verdadeiras. Se o resultado anterior for falso na primeira operação, a segunda operação não será executada.

declare
v_sal	number:=&sal;
v_job	varchar2(20):=&job;
begin
if (check_sal(v_sal) > 5000) AND (v_job = '销售') --判断执行条件
then
dbms_output.put_line('符合匹配的and条件');
end if;
end;

Este código tem um risco de desempenho. check_sal envolve algumas verificações de lógica de negócios. Se a função check_sal for chamada primeiro, essa função sempre será chamada. Portanto, por considerações de desempenho, o julgamento de v_job deve sempre ser colocado antes e antes da frase.

declare
v_sal	number:=&sal;
v_job	varchar2(20):=&job;
begin
if (v_job='销售') and (check_sal(v_sal) > 5000)
then
dbms_output.put_line('符合匹配的and条件');
end if;
end;

Evite conversões implícitas de tipo

Acho que você gosta

Origin blog.csdn.net/qq_38696286/article/details/119213244
Recomendado
Clasificación