分析 Snowpark Python 用户定义函数处理程序

您可以使用内置的代码分析器了解执行处理程序代码所消耗的时间或内存。分析器生成的信息描述了执行处理程序的每行代码所花费的时间或内存。

使用分析器可以生成报告,每次专注于以下其中一个方面:

  • 每行代码的执行时间,显示每行代码被执行的次数、执行所花费的时间等。

  • 每行代码的内存使用量,显示每行代码消耗的内存量。

分析器将生成的报告保存到内部 :doc:` 事件表 </developer-guide/logging-tracing/event-table-columns>`。您可以使用专为访问该表而设计的函数来检索结果。

备注

分析会对 Python 执行引入性能开销,并可能影响查询的性能。它用于开发和测试,不得在持续的生产工作负载中启用。

所需权限

要管理和使用存储在 SNOWFLAKE.LOCAL.PROFILER_EVENTS_RAW 事件表中的分析器结果数据,必须使用以下角色:

应用程序角色

备注

PROFILER_EVENTS_ADMIN

管理存储分析器数据的事件表中的数据(包括选择、截断或删除记录)时所需。

PROFILER_USER

从事件表读取分析器结果时所需。

有关授予应用程序角色的更多信息,请参阅 GRANT APPLICATION ROLE。以下示例使用 ACCOUNTADMIN 角色将应用程序角色 PROFILER_USER 授予用户。

USE ROLE ACCOUNTADMIN;
CREATE ROLE PROFILER_ROLE;
GRANT APPLICATION ROLE SNOWFLAKE.PROFILER_USER TO ROLE PROFILER_ROLE;
GRANT ROLE PROFILER_ROLE TO USER some_user;

限制

  • 查询执行后,分析器的结果可能需要 15-20 秒才能准备就绪。

  • 如果 UDF 执行失败,则不会保存分析器输出。

  • 不支持递归分析。仅会对指定模块的顶层函数进行分析。不会分析在函数内部定义的函数。

  • 不支持分析第三方模块。

  • 不支持对通过 snowflake.snowpark API 在客户端上创建的 UDFs 进行分析。

  • 不分析通过 joblib 并行运行的 Python 函数。

  • UDTFs 不受支持。

  • 时间以挂钟时间衡量,而不是 CPU 时间。

用途

设置分析器后,只需执行 UDF 即可生成分析器输出。在 UDF 执行完毕后,分析器的输出将写入内部事件表。您可以通过系统函数 提取分析器输出

按照代码中的以下步骤设置和使用分析器:

  1. 启用分析器并设置配置文件报告应关注的内容。

  2. 执行 UDF。

  3. 查看分析输出。

通过指定分析器的关注点来启用分析器

要启用分析器,请设置以下会话参数之一:

-- To enable profiling that focuses on activity per line
ALTER SESSION SET ACTIVE_PYTHON_PROFILER = 'LINE';

-- To enable profiling that focuses on memory usage
ALTER SESSION SET ACTIVE_PYTHON_PROFILER = 'MEMORY';

备注

分析会给 Python 执行引入性能开销。您应该在开发和测试期间分析代码。不要对连续生产工作负载启用分析。

指定要分析的代码

默认情况下,分析器会分析与 UDF 声明内联定义的方法。换句话说,分析器将分析处理程序中定义的所有方法。

对于以下 UDF 示例,分析器将分析 handler 方法和 helper 方法。

CREATE OR REPLACE function my_udf()
  RETURNS VARIANT
  LANGUAGE PYTHON
  RUNTIME_VERSION = 3.11
  PACKAGES = ('other_package')
  HANDLER = 'handler'
  AS $$
from other_package import some_method

def helper():
...

def handler():
...
$$;

指定要分析的外部代码

您可以指定分析器应分析在 UDF 声明之外定义的处理程序代码,例如从暂存区导入的代码。

要指定用于分析的外部代码,请将 PYTHON_UDF_PROFILER_MODULES 会话参数的值设置为包含代码的模块的逗号分隔列表。

ALTER SESSION SET PYTHON_UDF_PROFILER_MODULES = 'test_python_import_main, test_python_import_module';

当您执行导入这些模块的 UDF 时,分析器将在其分析输出中包含指定的模块。

以下示例中的代码显示了从指定模块导入代码的 UDF:

CREATE OR REPLACE function test_udf_1()
  RETURNS STRING
  LANGUAGE PYTHON
  RUNTIME_VERSION = 3.11
  HANDLER = 'test_python_import_main.my_udf'
  IMPORTS = ('@stage1/test_python_import_main.py', '@stage2/test_python_import_module.py');

执行用户定义函数

启用分析器后,执行您的用户定义函数 (UDF) 以开始分析。

默认情况下,分析器会分析模块中定义的方法。有关从导入的文件中注册其他模块以进行分析的信息,请参阅 指定要分析的代码 以了解更多信息。

SELECT return_mean(my_col) FROM MY_TABLE;

查看分析输出

  • 要查看分析输出,请查询内部 事件表

分析结果通常在 UDF 执行完成后的 15-20 秒内出现在事件表中。您可以使用表系统函数 GET_PYTHON_UDF_PROFILER_OUTPUT 访问输出。

以下示例中的代码显示了对事件表进行的分析器结果查询。作为实参指定的 query_id 是已启用分析的 UDF 查询的查询 ID。

SELECT * FROM TABLE(SNOWFLAKE.LOCAL.GET_PYTHON_UDF_PROFILER_OUTPUT(<query_id>));

分析结果

查看分析器结果时,您将看到一份报告,该报告根据您指定的是行报告分析还是内存报告分析而有所不同。

内存分析器输出将如下所示:

Handler Name: return_mean
Python Runtime Version: 3.12
Modules Profiled: ['return_mean_module']
Extension Function ID: 1

File: _udf_code.py
Function: return_mean at line 2

Line #    Mem usage    Increment  Occurrences    Line Contents
==============================================================
     2    107.0 MiB    107.0 MiB           1    def return_mean():
     3    144.6 MiB     37.6 MiB           1        import numpy as np
     4
     5                                              # Generate a numpy array with 10 random integers between 1 and 100
     6                                              # np.random.randint(low, high, size)
     7    147.3 MiB      2.7 MiB           1        random_array = np.random.randint(1, 101, 10)
     8
     9                                              # Use a numpy function to calculate the mean
    10    147.3 MiB      0.0 MiB           1        mean_value = np.mean(random_array)
    11
    12    147.3 MiB      0.0 MiB           1        count = 0
    13    147.3 MiB      0.0 MiB         101        for i in range(100):
    14    147.3 MiB      0.0 MiB         100            count = count + 1
    15
    16    147.3 MiB      0.0 MiB           1        return mean_value

代码行分析器输出将如下所示:

Handler Name: return_mean
Python Runtime Version: 3.12
Extension Function ID: 1
Modules Profiled: ['return_mean_module']
Timer Unit: 0.001 s

Total Time: 0.229063 s
File: _udf_code.py
Function: return_mean at line 2

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
     2                                           def return_mean():
     3         1        206.1    206.1     90.0      import numpy as np
     4
     5                                               # Generate a numpy array with 10 random integers between 1 and 100
     6                                               # np.random.randint(low, high, size)
     7         1         22.8     22.8     10.0      random_array = np.random.randint(1, 101, 10)
     8
     9                                               # Use a numpy function to calculate the mean
    10         1          0.1      0.1      0.0      mean_value = np.mean(random_array)
    11
    12         1          0.0      0.0      0.0      count = 0
    13       101          0.0      0.0      0.0      for i in range(100):
    14       100          0.0      0.0      0.0          count = count + 1
    15
    16         1          0.0      0.0      0.0      return mean_value