Производительность UDF SQL против UDF Javascript в SnowFlake - PullRequest
0 голосов
/ 21 мая 2018

Мы пытаемся реализовать добавление значений интервалов в Snowflake. Так как в Snowflake не поддерживается тип данных интервалов, мы пытаемся реализовать то же самое с использованием UDF.Мы конвертируем интервалы в секунды, и после получения общего количества секунд мы конвертируем общее количество секунд в требуемый тип целевого интервала.

Мы реализовали ту же логику, используя SQL UDF и Javascript UDF.

Javascript UDF

    create or replace function js_interval(interval_1 string, interval_sign_1 double, interval_2 string, interval_sign_2 double)
  returns string
  language javascript
  strict
  as '     
  if ((INTERVAL_1.substring(0,1)=="-"))
  {
    var res = INTERVAL_1.split(":");
    var res2=(res[1]*-60+res[0]*3600);
    var res3= -1*res[2];
  }
  else
  {
    var res = INTERVAL_1.split(":");
    var res2=(res[1]*60+res[0]*3600);
    var res3= res[2];
  }
  if ((INTERVAL_2.substring(0,1)=="-"))
  {
     var res11 = INTERVAL_2.split(":");
     var res22=(res11[1]*-60+res11[0]*3600);
     var res33= -1*res11[2];
  }
  else
  {
     var res11 = INTERVAL_2.split(":");
     var res22=(res11[1]*60+res11[0]*3600);
     var res33= res11[2];
  }
  if(INTERVAL_SIGN_1 > 0)
  { 
    var result1= res2*1+res3*1;
  }
  else
  {
    var result1=(res2*1+res3*1)*-1;
  }
  if(INTERVAL_SIGN_2 > 0)
  { 
    var result2= res22*1+res33*1;
  }
  else
  {
    var result2=(res22*1+res33*1)*-1;
  }
  var final_sec= result1+result2;

  if (final_sec < 0 )
  {
    return "-"+String(Math.trunc(Math.abs(final_sec)/3600))+":"+String(Math.trunc(Math.abs(final_sec)/60)%60)+":"+String(Math.abs(final_sec)%60);
  }    
  else
  {
    return String(Math.trunc(Math.abs(final_sec)/3600))+":"+String(Math.trunc(Math.abs(final_sec)/60)%60)+":"+String(Math.abs(final_sec)%60);
  }
';

SQL UDF

 create or replace function addIntervalsH2S ( interval_1 varchar, interval_type_1 varchar , interval_sign_1 int, interval_2 varchar, interval_type_2 varchar, interval_sign_2 int )
  returns varchar 
  as
  'select trunc((((split_part(interval_1,\':\',1)*3600+split_part(interval_1,\':\',2)*60+split_part(interval_1,\':\',3))*interval_sign_1)+((split_part(interval_2,\':\',1)*3600+split_part(interval_2,\':\',2)*60+split_part(interval_2,\':\',3))*interval_sign_2))/3600)||\':\'||mod(trunc((((split_part(interval_1,\':\',1)*3600+split_part(interval_1,\':\',2)*60+split_part(interval_1,\':\',3))*interval_sign_1)+((split_part(interval_2,\':\',1)*3600+split_part(interval_2,\':\',2)*60+split_part(interval_2,\':\',3))*interval_sign_2))/60),60)||\':\'||mod((((split_part(interval_1,\':\',1)*3600+split_part(interval_1,\':\',2)*60+split_part(interval_1,\':\',3))*interval_sign_1)+((split_part(interval_2,\':\',1)*3600+split_part(interval_2,\':\',2)*60+split_part(interval_2,\':\',3))*interval_sign_2)),60)
  end';                

Производительность UDF на основе Javascript для запроса на добавление интервалов вложенного уровняэто лучше, чем UDF на основе SQL.

В чем может быть причина, объясняющая огромную разницу в производительности?

1 Ответ

0 голосов
/ 30 мая 2018

Мы определили проблему с подзапросами в нашем SQL, когда даже в простом запросе, например,

SELECT (SELECT expression1) + (SELECT expression2)

оба подзапроса оцениваются как отдельные "шаги" выполнения (если expression1/2 не очень прост),Каждый «шаг» подобен полностью отдельному запросу, что делает его медленным.

Поскольку пользовательские функции SQL внутренне разворачиваются в подзапросы, это приводит к тому, что каждый вызов пользовательской функции SQL, начинающейся с SELECT, будет оцениваться с использованиемдополнительный шаг, что делает его значительно медленнее.

Решение?Попробуйте удалить ключевое слово SELECT из начала SQL UDF, это должно сделать его намного быстрее.Это похоже на переписывание приведенного выше запроса в

SELECT (expression1) + (expression2)
...