Criação de perfil do código do manipulador de procedimento Python¶
Você pode descobrir quanto tempo ou memória foi gasto na execução do código do manipulador usando o criador de perfil do código integrado. O criador de perfil gera informações que descrevem quanto tempo ou memória foi gasto na execução de cada linha do manipulador de procedimento.
Usando o criador de perfil, você pode gerar relatórios que se concentram em um dos seguintes itens de cada vez:
Quantidade de tempo por linha, no qual o relatório mostra o número de vezes que uma linha foi executada, quanto tempo levou a execução e assim por diante.
Quantidade de uso de memória por linha, no qual o relatório mostra a quantidade de memória consumida por linha.
O criador de perfil salva o relatório gerado em um estágio de usuário interno do Snowflake que você especificar. Você pode ler a saída do criador de perfil usando a função de sistema GET_PYTHON_PROFILER_OUTPUT (SNOWFLAKE.CORE).
Nota
A criação de perfil introduz uma sobrecarga de desempenho na execução do Python e pode afetar o desempenho da consulta. Ele se destina ao desenvolvimento, testes e solução de problemas e não deve ser ativado em cargas de trabalho de produção contínua.
Privilégios obrigatórios¶
A configuração do parâmetro de nível de sessão não aciona a verificação de privilégios, mas quando um procedimento armazenado é executado com o parâmetro de sessão ACTIVE_PYTHON_PROFILER como LINE ou MEMORY, o Snowflake verifica os seguintes privilégios.
Você deve ter privilégios de leitura/gravação no estágio de saída de criação de perfil.
Se o procedimento armazenado com perfil for um procedimento armazenado com direitos do chamador, você deverá usar uma função com privilégio USAGE no procedimento armazenado.
Se o procedimento armazenado com perfil for um procedimento armazenado com direitos do proprietário, você deverá usar uma função com privilégio OWNERSHIP no procedimento armazenado.
Limitações¶
Somente procedimentos armazenados são suportados. O suporte para UDFs ainda não está disponível.
Não há suporte para criação de perfil recursiva. Somente as funções de nível superior dos módulos especificados são analisadas. As funções definidas dentro de funções não são.
Não há suporte para a criação de perfis de procedimentos armazenados criados no lado do cliente por meio da
snowflake.snowpark
API (por exemplo, procedimentos armazenados criados emSession.sproc.register
).As funções Python executadas em paralelo por meio do
joblib
não serão analisadas.Os procedimentos armazenados definidos pelo sistema não podem ser analisados. Eles não produzirão nenhum resultado.
Uso¶
Depois de configurar o criador de perfil para uso, você pode usá-lo simplesmente chamando o procedimento armazenado para gerar a saída do criador de perfil. Depois que o procedimento termina de ser executado, a saída do criador de perfil é gravada em um arquivo no estágio que você especificar. Você pode obter a saída do criador de perfil usando uma função do sistema.
Siga estas etapas para configurar e usar o criador de perfil:
Especifique o estágio do Snowflake onde a saída do perfil deve ser gravada.
Defina o parâmetro PYTHON_PROFILER_TARGET_STAGE como o nome totalmente qualificado do estágio.
Ative o criador de perfil e especifique em que o perfil deve se concentrar.
Defina o parâmetro de sessão ACTIVE_PYTHON_PROFILER.
Chame o procedimento armazenado.
Depois que o criador de perfil estiver ativado, chame seu procedimento armazenado.
Visualize a saída de criação de perfil.
No fim da execução, o resultado da criação de perfil será carregado como um arquivo no estágio de saída com o padrão de nomenclatura
<query_id>_<sproc_name>.lprof
ou<query_id>_<sproc_name>.mprof
.
Especifique o estágio do Snowflake em que a saída do perfil deve ser gravada¶
Antes de executar o criador de perfil, você deve especificar um estágio no qual o relatório será salvo. Para especificar o estágio, defina o parâmetro PYTHON_PROFILER_TARGET_STAGE como o nome totalmente qualificado do estágio.
Use um estágio temporário para armazenar a saída somente durante a sessão.
Use um estágio permanente para preservar a saída do criador de perfil fora do escopo de uma sessão.
O código no exemplo a seguir cria um estágio temporário de profiler_output
para receber a saída do criador de perfil.
USE DATABASE my_database;
USE SCHEMA my_schema;
CREATE TEMPORARY STAGE profiler_output;
ALTER SESSION SET PYTHON_PROFILER_TARGET_STAGE = "my_database.my_schema.profiler_output";
Como ativar o criador de perfil e especificar em que o perfil deve se concentrar¶
Defina o parâmetro de sessão ACTIVE_PYTHON_PROFILER com um valor que especifique o tipo de relatório de perfil que você deseja gerar.
Para que o perfil se concentre na atividade de uso da linha, defina o parâmetro como o valor
LINE
(não diferencia maiúsculas de minúsculas), conforme mostrado abaixo:ALTER SESSION SET ACTIVE_PYTHON_PROFILER = 'LINE';
Para que o perfil se concentre na atividade de uso de memória, defina o parâmetro como o valor
MEMORY
(não diferencia maiúsculas de minúsculas), conforme mostrado abaixo:ALTER SESSION SET ACTIVE_PYTHON_PROFILER = 'MEMORY';
Como chamar o procedimento armazenado¶
Depois que o criador de perfil estiver ativado, chame seu procedimento armazenado.
CALL YOUR_STORED_PROCEDURE();
Por padrão, o criador de perfil traçará o perfil dos métodos definidos no módulo do usuário. Você também pode registrar outros módulos no perfil. Para obter mais informações, consulte Módulos adicionais de perfil.
Como exibir a saída de criação de perfil¶
No fim da execução, o resultado da criação de perfil será carregado como um arquivo no estágio de saída com o padrão de nomenclatura <query_id>_<sproc_name>.lprof
ou <query_id>_<sproc_name>.mprof
.
A saída pode ser acessada por meio de uma função do sistema GET_PYTHON_PROFILER_OUTPUT no banco de dados SNOWFLAKE.
O formato da assinatura da função do sistema é o seguinte:
SELECT SNOWFLAKE.CORE.GET_PYTHON_PROFILER_OUTPUT(<query_id>);
Substitua <query_id>
pelo ID da consulta do procedimento armazenado para a qual a criação de perfil foi ativada.
Você também pode acessar diretamente o arquivo de saída no estágio de saída. Para obter mais informações, consulte Exibição de arquivos preparados.
Nota
A função do sistema procura arquivos de saída de criação de perfil do estágio especificado com o parâmetro PYTHON_PROFILER_TARGET_STAGE.
A saída de criação de perfil para procedimentos armazenados filhos não é anexada à saída do procedimento pai. Para visualizar a saída de um procedimento armazenado filho, chame explicitamente a função do sistema no ID de consulta do procedimento filho.
Inclusão de módulos adicionais para criação de perfis¶
Você pode incluir módulos de criação de perfil que não são incluídos por padrão. Para incluir módulos adicionais para criação de perfil, defina o parâmetro PYTHON_PROFILER_MODULES com os nomes dos módulos que você deseja incluir.
Por padrão, os métodos definidos no seu módulo serão analisados. Esses métodos incluem os seguintes:
O método do manipulador
Métodos definidos no módulo
Métodos importados de pacotes ou outros módulos.
No exemplo abaixo, handler
, helper
e some_method
terão todos criação de perfil por padrão.
CREATE OR REPLACE PROCEDURE my_sproc()
RETURNS VARIANT
LANGUAGE PYTHON
RUNTIME_VERSION = 3.10
PACKAGES = ('snowflake-snowpark-python', 'other_package')
HANDLER='handler'
AS $$
from other_package import some_method
def helper():
...
def handler(session):
...
$$;
Inclusão de módulos com o parâmetro PYTHON_PROFILER_MODULES¶
Você pode usar o parâmetro PYTHON_PROFILER_MODULES para incluir módulos de criação de perfil que não seriam incluídos por padrão. Quando você inclui um módulo dessa forma, todas as funções usadas a partir desse módulo serão incluídas na saída do criador de perfil. Por padrão, o valor do parâmetro PYTHON_PROFILER_MODULES é uma cadeia de caracteres vazia (''
), na qual o perfil traçaria o perfil apenas do código do manipulador em linha, se houver.
Para incluir módulos para criação de perfil, especifique seus nomes como o valor do parâmetro em uma lista separada por vírgulas, conforme ilustrado abaixo.
ALTER SESSION SET PYTHON_PROFILER_MODULES = 'module_a, my_module';
Criação de perfil do código do manipulador em estágios¶
Para traçar o perfil do código do manipulador que é preparado em vez de inline, inclusive funções auxiliares, você deve especificar explicitamente o manipulador preparado para a criação de perfil usando o parâmetro PYTHON_PROFILER_MODULES.
Por padrão, o criador de perfil não traça o perfil do código do manipulador que é em estágio, em vez de inline — ou seja, quando o módulo do manipulador é especificado com a cláusula IMPORTS.
Por exemplo, por padrão, esse procedimento não gerará nenhuma saída detalhada de criação de perfil.
CREATE OR REPLACE PROCEDURE test_udf_1()
RETURNS STRING
LANGUAGE PYTHON
RUNTIME_VERSION = '3.8'
PACKAGES=('snowflake-snowpark-python')
HANDLER = 'test_python_import_main.my_udf'
IMPORTS = ('@stage1/test_python_import_main.py', '@stage2/test_python_import_module.py');
Para incluir o código em estágios para a criação de perfil, especifique os nomes dos módulos em estágios como o valor do parâmetro PYTHON_PROFILER_MODULES em uma lista separada por vírgulas, conforme ilustrado abaixo.
ALTER SESSION SET PYTHON_PROFILER_MODULES = 'test_python_import_main, test_python_import_module';
Exemplo¶
O código neste exemplo ilustra como usar o criador de perfil para gerar e recuperar um relatório de uso de linha.
CREATE OR REPLACE PROCEDURE last_n_query_duration(last_n number, total number)
RETURNS string
LANGUAGE PYTHON
RUNTIME_VERSION=3.8
PACKAGES=('snowflake-snowpark-python')
HANDLER='main'
AS
$$
import snowflake.snowpark.functions as funcs
def main(session, last_n, total):
# create sample dataset to emulate id + elapsed time
session.sql('''
CREATE OR REPLACE TABLE sample_query_history (query_id INT, elapsed_time FLOAT)
''').collect()
session.sql('''
INSERT INTO sample_query_history
SELECT
seq8() AS query_id,
uniform(0::float, 100::float, random()) as elapsed_time
FROM table(generator(rowCount => {0}));'''.format(total)).collect()
# get the mean of the last n query elapsed time
df = session.table('sample_query_history').select(
funcs.col('query_id'),
funcs.col('elapsed_time')).limit(last_n)
pandas_df = df.to_pandas()
mean_time = pandas_df.loc[:, 'ELAPSED_TIME'].mean()
del pandas_df
return mean_time
$$;
CREATE TEMPORARY STAGE profiler_output;
ALTER SESSION SET PYTHON_PROFILER_TARGET_STAGE = "my_database.my_schema.profiler_output";
ALTER SESSION SET ACTIVE_PYTHON_PROFILER = 'LINE';
-- Sample 1 million from 10 million records
CALL last_n_query_duration(1000000, 10000000);
SELECT SNOWFLAKE.CORE.GET_PYTHON_PROFILER_OUTPUT(last_query_id());
A saída do criador de perfil de linha terá a seguinte aparência:
Handler Name: main
Python Runtime Version: 3.8
Modules Profiled: ['main_module']
Timer Unit: 0.001 s
Total Time: 8.96127 s
File: _udf_code.py
Function: main at line 4
Line # Hits Time Per Hit % Time Line Contents
==============================================================
4 def main(session, last_n, total):
5 # create sample dataset to emulate id + elapsed time
6 1 122.3 122.3 1.4 session.sql('''
7 CREATE OR REPLACE TABLE sample_query_history (query_id INT, elapsed_time FLOAT)''').collect()
8 2 7248.4 3624.2 80.9 session.sql('''
9 INSERT INTO sample_query_history
10 SELECT
11 seq8() AS query_id,
12 uniform(0::float, 100::float, random()) as elapsed_time
13 1 0.0 0.0 0.0 FROM table(generator(rowCount => {0}));'''.format(total)).collect()
14
15 # get the mean of the last n query elapsed time
16 3 58.6 19.5 0.7 df = session.table('sample_query_history').select(
17 1 0.0 0.0 0.0 funcs.col('query_id'),
18 2 0.0 0.0 0.0 funcs.col('elapsed_time')).limit(last_n)
19
20 1 1528.4 1528.4 17.1 pandas_df = df.to_pandas()
21 1 3.2 3.2 0.0 mean_time = pandas_df.loc[:, 'ELAPSED_TIME'].mean()
22 1 0.3 0.3 0.0 del pandas_df
23 1 0.0 0.0 0.0 return mean_time
A saída do criador de perfil de memória terá a seguinte aparência:
ALTER SESSION SET ACTIVE_PYTHON_PROFILER = 'MEMORY';
Handler Name: main
Python Runtime Version: 3.8
Modules Profiled: ['main_module']
File: _udf_code.py
Function: main at line 4
Line # Mem usage Increment Occurrences Line Contents
=============================================================
4 245.3 MiB 245.3 MiB 1 def main(session, last_n, total):
5 # create sample dataset to emulate id + elapsed time
6 245.8 MiB 0.5 MiB 1 session.sql('''
7 CREATE OR REPLACE TABLE sample_query_history (query_id INT, elapsed_time FLOAT)''').collect()
8 245.8 MiB 0.0 MiB 2 session.sql('''
9 INSERT INTO sample_query_history
10 SELECT
11 seq8() AS query_id,
12 uniform(0::float, 100::float, random()) as elapsed_time
13 245.8 MiB 0.0 MiB 1 FROM table(generator(rowCount => {0}));'''.format(total)).collect()
14
15 # get the mean of the last n query elapsed time
16 245.8 MiB 0.0 MiB 3 df = session.table('sample_query_history').select(
17 245.8 MiB 0.0 MiB 1 funcs.col('query_id'),
18 245.8 MiB 0.0 MiB 2 funcs.col('elapsed_time')).limit(last_n)
19
20 327.9 MiB 82.1 MiB 1 pandas_df = df.to_pandas()
21 328.9 MiB 1.0 MiB 1 mean_time = pandas_df.loc[:, 'ELAPSED_TIME'].mean()
22 320.9 MiB -8.0 MiB 1 del pandas_df
23 320.9 MiB 0.0 MiB 1 return mean_time