【问题标题】:How to debug a Snowflake stored procedure?如何调试雪花存储过程?
【发布时间】:2019-10-30 10:26:00
【问题描述】:

我正在使用雪花云数据库,请帮助我调试程序或功能的工具。

【问题讨论】:

    标签: procedure snowflake-cloud-data-platform


    【解决方案1】:

    以下 Snowflake Javascript 存储过程是我用来开始新存储过程的模板。它包含大量的调试技巧,例如:

    • 它有一个“我在哪里?”变量让您了解您在代码中的位置
    • 随着进程的进行,它会在一个数组中收集信息
    • 它将该数组返回到调用命令的标准输出
    • 它有一个异常块的“良好开端”,如果失败,异常块的内容也会在调用存储过程时被推送到标准输出。

    我一直想要添加的是在代码中设置一个查询标记,这在查看查询历史记录时会很有帮助,以便轻松识别在执行存储过程中使用的 SQL 命令。

    这与最终的“调试技巧”“联系在一起”——在开发或测试环境中开发存储过程时,尤其是在构建动态 SQL 语句时,您应该始终查看查询历史记录(代码执行的实际查询)。查看您的查询历史记录是必须做的,它将准确地向您显示运行的命令以及它们运行的​​操作顺序。

    这是它使用的示例表的代码,希望对您有所帮助...丰富

    CREATE OR REPLACE TABLE test_scripts (
       load_seq  number,
       script    varchar(2000)
       );
    
    INSERT INTO test_scripts values 
       (1, 'SELECT current_timestamp();'),
       (2, 'SELECT current_warehouse();'),
       (3, 'SELECT COUNT(*) FROM snowflake.account_usage.tables;'),
       (4, 'SELECT current_date();'),
       (5, 'SELECT current_account();'),
       (6, 'SELECT COUNT(*) FROM snowflake.account_usage.tables;'),
       (7, 'SELECT ''RICH'';');
    
    select * from test_scripts;
    
    
    CREATE OR REPLACE PROCEDURE sp_test(p1 varchar, p2 varchar)
      RETURNS ARRAY
    LANGUAGE javascript
    EXECUTE AS caller
    AS 
    $$
    //note:  you can change the RETURN to VARCHAR if needed
    //       but the array "looks nice"
    try {
       var whereAmI = 1;
       var return_array = [];
       var counter = 0;
    
       var p1_str = "p1: " + P1
       var p2_str = "p2: " + P2
       var load_seq = P1;
       var continue_flag = P2;
    
       whereAmI = 2;
       return_array.push(p1_str)
       return_array.push(p2_str)
    
       whereAmI = 3;
       //which SQL do I want to run?
       if (continue_flag=="YES") {
           return_array.push("query 1")
           var sqlquery = "SELECT * FROM test_scripts WHERE load_seq >= " + load_seq + " order by 1, 2;";
           }
       else {
           return_array.push("query 2")
           var sqlquery = "SELECT * FROM test_scripts WHERE load_seq = " + load_seq + " order by 1, 2;";
           }
    
       whereAmI = 4;
       //begin the run of grabbing the commands
       var stmt = snowflake.createStatement( {sqlText: sqlquery} );
       var rs = stmt.execute();
    
       whereAmI = 5;
       // Loop through the results, processing one row at a time... 
       while (rs.next())  {
           counter = counter + 1;
           var tmp_load_seq = rs.getColumnValue(1);
           var tmp_script = rs.getColumnValue(2);
    
           var tmp_rs = snowflake.execute({sqlText: tmp_script});
           tmp_rs.next();
           var tmp_col1 = tmp_rs.getColumnValue(1);
           return_array.push("tmp_col1: " + tmp_col1)
    
           }
    
       whereAmI = 6;
       return_array.push("end process - counter: " + counter)
    
       return return_array;
       }
    
    catch (err) {
       return_array.push("error found")
       return_array.push(whereAmI)
       return_array.push(err)
       return return_array;
    }
    
    $$;
    
    CALL sp_test(3, 'NO');
    

    【讨论】:

      【解决方案2】:

      我不相信 Snowflake 的存储过程有任何编辑器/调试器。几个选项:

      1. 您可以将代码分解成更小的部分并尝试进行故障排除
      2. 使用日志表并经常插入到日志表中,因此您可以查看日志表找出问题所在

      【讨论】:

        【解决方案3】:

        不幸的是,没有一种环境可以统治所有这些 1. 在工作表或编辑器中编写 SQL 2. 在支持 JS 的编辑器中编写您的 SPROC 代码 3. 在工作表或编辑器中将它们合并在一起 4. SPROCS 中的单元测试,如上图@Rich Murmane

        我通常只是在工作表中写 SPROCS,但这不是最佳的

        【讨论】:

          【解决方案4】:

          日志在这里是你的朋友,因为没有调试器。一般来说,为 db 存储过程查找和使用调试器很难实现。不是不可能,只是不太可能。

          这是一个不错的选择:

          CREATE or replace PROCEDURE do_log(MSG STRING)
           RETURNS STRING
           LANGUAGE JAVASCRIPT
           EXECUTE AS CALLER
          AS $$
           
           //see if we should log - checks for do_log = true session variable
           try{
              var foo = snowflake.createStatement( { sqlText: `select $do_log` } ).execute();
           } catch (ERROR){
              return; //swallow the error, variable not set so don't log
           }
           foo.next();
           if (foo.getColumnValue(1)==true){ //if the value is anything other than true, don't log
              try{
                  snowflake.createStatement( { sqlText: `create temp table identifier ($log_table) if not exists (ts number, msg string)`} ).execute();
                  snowflake.createStatement( { sqlText: `insert into identifier ($log_table) values (:1, :2)`, binds:[Date.now(), MSG] } ).execute();
              } catch (ERROR){
                  throw ERROR;
              }
           }
           $$
          ;
          

          然后在存储过程中,要调试在顶部添加一个log函数:

          function log(msg){
              snowflake.createStatement( { sqlText: `call do_log(:1)`, binds:[msg] } ).execute();
          }
          
          

          然后上面调用存储过程:

          set do_log = true; --true to enable logging, false (or undefined) to disable
          set log_table = 'my_log_table'; --The name of the temp table where log messages go
          

          那么在实际的存储过程中你需要添加一些日志记录行:

          log('this is another log message'); 
          

          然后像往常一样调用存储过程。然后select 来自my_log_table

          重要提示:这使用临时表,因此您将无法在不同的 Snowflake 连接中从该日志记录表中读取。这意味着,如果您使用工作表编辑器,则需要将所有这些内容保存在同一张工作表上。

          “借”自:https://community.snowflake.com/s/article/Snowflake-Stored-Procedure-Logging

          【讨论】:

            猜你喜欢
            • 2020-05-23
            • 2021-10-17
            • 2021-10-01
            • 2021-06-22
            • 1970-01-01
            • 2021-07-12
            • 2020-09-28
            • 2021-02-13
            • 2021-08-25
            相关资源
            最近更新 更多