Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Oracle Новый топик    Ответить
 PL/SQL vs JAVA vs C  [new]
Кобанчег
Member

Откуда: Рахів
Сообщений: 841
Привет!

Решил опубликовать свое сравнение PL/SQL vs JAVA vs C на двух достаточно разных задачах. Может кому-то будет полезно, а возможно я что-то не учел. :)

1.
Имеются 2n элементов бинарного дерева. Значение каждого элемента может быть вычислено по функции от значения индекса, то есть хранить их не обязательно. Значение родительского элемента определяется значением некоторой функции от значений детей. Необходимо посчитать значение корня дерева.
Исключительно для простоты элемент равен индексу, родитель - равен сумме детей. Понятно, что в этом случае, родитель - сумма арифметической прогрессии, но тем не менее алгоритм строится для универсального случая.
+ PLSQL
create or replace function getvalue_plsql(n in binary_integer)
  return number is
  value number;
  tmp   binary_integer;
  j     binary_integer;
  ind   binary_integer := 0;
  stack sys.odcinumberlist := sys.odcinumberlist();
begin
  stack.extend(n + 1);
  for i in 0 .. power(2, n) - 1 loop
    value := i; -- function 1
    ind := ind + 1;
    stack(ind) := value;
    
    tmp   := 1;
    j     := 0;
    while true loop
      tmp := tmp * 2;
      if bitand(i, tmp - 1) <> tmp - 1 then
        exit;
      end if;
      j := j + 1;
    end loop;
    
    for k in 1 .. j loop
      stack(ind - 1) := stack(ind - 1) + stack(ind); -- function 2
      ind := ind - 1;
    end loop;
  end loop;

  return stack(1);
end getvalue_plsql;

+ C
#include <windows.h>

extern "C" _declspec(dllexport) double GetValue(int n)
{
  double value;
  double *stack = new double[n+1];
  int    i, j, k, ind = 0;
  int    qty = 1<<n;

  for (i=0;i<qty;i++)
  {
    value = i;
    stack[ind++]=value;

    for (j=0;((2<<j)-1)==(i&((2<<j)-1));j++) {};
    for (k=1;k<=j;k++) {stack[--ind-1]+=stack[ind];}
  }

  return stack[0];
}

+ JAVA
package pkg_java;

public class GetValue
{
public static double DoIt(int n)
{
  double value;
  double[] stack = new double[n+1];
  int    i, j, k, ind = 0;
  int    qty = 1<<n;

  for (i=0;i<qty;i++)
  {
    value = i;
    stack[ind++]=value;

    for (j=0;((2<<j)-1)==(i&((2<<j)-1));j++) {};
    for (k=1;k<=j;k++) {stack[--ind-1]+=stack[ind];}
  }

  return stack[0];
}
}

+ Вспомогательные действия
C:\Windows\system32>loadjava -user user/pass -oci8 H:\GetValue.java
create or replace library getvalue_lib as 'C:\app\user\product\11.2.0\dbhome_1\BIN\getvalue.dll'
/
create or replace function getvalue_c(n in binary_integer)
  return binary_double as
  external
  library getvalue_lib name "GetValue"
  language C
  parameters(n long);
/
create or replace function GetValue_JAVA(n in number)
  return number as
  language java name 'pkg_java.GetValue.DoIt(int) return double';
/

Результаты:
set timing on
select to_char(getvalue_plsql(25), '00000000000000000000') result from dual;

RESULT
---------------------
 00000562949936644096

Elapsed: 00:00:29.49
select to_char(getvalue_java(25) , '00000000000000000000') result from dual;

RESULT
---------------------
 00000562949936644096

Elapsed: 00:00:06.89
select to_char(getvalue_c(25)    , '00000000000000000000') result from dual;

RESULT
---------------------
 00000562949936644096

Elapsed: 00:00:00.22
select to_char(getvalue_plsql(28), '00000000000000000000') result from dual;

RESULT
---------------------
 00036028796884746240

Elapsed: 00:04:01.84
select to_char(getvalue_java(28) , '00000000000000000000') result from dual;

RESULT
---------------------
 00036028796884746200

Elapsed: 00:00:54.74
select to_char(getvalue_c(28)    , '00000000000000000000') result from dual;

RESULT
---------------------
 00036028796884746240

Elapsed: 00:00:01.62
Как видно процедура на С оказалась примерно в 130 раз быстрее чем на PL/SQL. И более чем в 30 раз быстрее чем на JAVA. То есть если необходима предельная скорость - однозначно С. С другой стороны с версии 11g были сделаны некоторые улучшения в выполнении PL/SQL типа Inline Optimization, Native Compilation. Это, возможно, позволило бы почти догнать по производительности JAVA, тем не менее я это здесь не использовал, поскольку в любом случае необходимость писать хранимки на JAVA представляется мне более чем сомнительной.
Обращаю внимание также, что при числе элементов 228 наблюдается погрешность в точности double в JAVA. Однако с binary_double в PL/SQL все еще печальнее: binary_double и number.

Поскольку в демонстрации выполняется всего один вызов функции - перейду к задаче 2.

2.
В таблице БД имеются два столбца, задача найти для каждой строки наибольшую общую подстроку для обоих столбцов. Это известная задача динамического программирования. Алгоритм описан здесь: Longest common substring.
+ PLSQL
create or replace function LCSubstr_PLSQL(S varchar2, T varchar2)
  return varchar2 is
  type t1 is table of binary_integer index by binary_integer;
  type t2 is table of t1 index by binary_integer;
  l      t2;
  z      binary_integer := 0;
  result varchar2(4000);
begin
  for i in 1 .. length(s) loop
    for j in 1 .. length(t) loop
      if substr(s, i, 1) = substr(t, j, 1) then
        if i = 1 or j = 1 then
          L(i)(j) := 1;
        else
          L(i)(j) := L(i - 1) (j - 1) + 1;
        end if;
        if L(i) (j) > z then
          z      := L(i) (j);
          result := substr(s, i - z + 1, z);
        end if;
      else
        L(i)(j) := 0;
      end if;
    end loop;
  end loop;
  return result;
end;

+ C
#include <windows.h>

#define MAX 240

int length(char *s)
{
  int i;
  for (i = 0; *s != '\0'; s++) i++;
  return i;
}

extern "C" _declspec(dllexport) char* LCSubstr(char *S, char *T)
{
  static char result[MAX];
  int L[MAX][MAX];

  int lS, lT;
  int i, j, k;
  int z = 0;

  lS = length(S);
  lT = length(T);

  for (i = 0; i<lS; i++)
    for (j = 0; j<lT; j++)
      if (S[i] == T[j])
      {
        if (i == 0 || j == 0)
          L[i][j] = 1;
        else
          L[i][j] = L[i-1][j-1]+1;
        if (L[i][j] > z)
        {
          z = L[i][j];
          for (k = 0; k<z; k++)
            result[k]=S[i-z+k+1];
          result[k+1]='\0';
        }
      }
      else
        L[i][j]=0;

  return result;
}

Данные для тестирования:
create table t as
select dbms_random.string('U',240) s1, dbms_random.string('U',240) s2
from dual
where rownum > 0
connect by level <= 1000;

Результаты:
select max(LCSubstr_C(s1,s2)) result from t;

RESULT
----------
ZZM

Elapsed: 00:00:00.46
select max(LCSubstr_PLSQL(s1,s2)) result from t;

RESULT
----------
ZZM

Elapsed: 00:00:20.08
Как видно разница уменьшилась, но запрос, с использованием функции на С все равно выполняется более чем в 40 раз быстрее чем с функцией на PL/SQL.

PS. Библиотеки на С были откомпилированы с помощью MinGW.
27 дек 11, 02:34    [11830447]     Ответить | Цитировать Сообщить модератору
 Re: PL/SQL vs JAVA vs C  [new]
mcureenab
Member

Откуда: Murmansk
Сообщений: 5928
Кобанчег
Понятно, что в этом случае, родитель - сумма арифметической прогрессии,


А ты не думаешь, что оптимизирующий компилятор C об это тоже догадался?
27 дек 11, 09:35    [11830821]     Ответить | Цитировать Сообщить модератору
 Re: PL/SQL vs JAVA vs C  [new]
Кобанчег
Member

Откуда: Рахів
Сообщений: 841
mcureenab
А ты не думаешь, что оптимизирующий компилятор C об это тоже догадался?
Это было б мощно, если б он был такой догадливый. :)
А на самом деле, если вместо функции родитель = правый_потомок + левый потомок использовать, например, родитель = (правый_потомок2 + левый потомок2)1/2, то положение дел не меняется.
27 дек 11, 12:14    [11832045]     Ответить | Цитировать Сообщить модератору
 Re: PL/SQL vs JAVA vs C  [new]
пришел и все
Guest
Кобанчег
PS. Библиотеки на С были откомпилированы с помощью MinGW.


Откомпилируй теперь на MSVC.

А в целом, об чем статья? Что C быстрее Java, а та быстрее PL/SQL? А мужики то и не знали поди...
27 дек 11, 12:28    [11832151]     Ответить | Цитировать Сообщить модератору
 Re: PL/SQL vs JAVA vs C  [new]
Кобанчег
Member

Откуда: Рахів
Сообщений: 841
пришел и все
А в целом, об чем статья? Что C быстрее Java, а та быстрее PL/SQL? А мужики то и не знали поди...
Конечно все всё знали: числомолотилка в Oracle.
27 дек 11, 12:41    [11832228]     Ответить | Цитировать Сообщить модератору
 Re: PL/SQL vs JAVA vs C  [new]
Vint
Member

Откуда: Москва
Сообщений: 4564
Кобанчег,
имхо не хватает Вашего личного вывода. без вывода это констатация давно известного факта.
зы.Насчет числомолотилки - страницы с третьей лично мне стало понятно что автор упёрся в стенку и махал красным флагом.
27 дек 11, 13:22    [11832576]     Ответить | Цитировать Сообщить модератору
 Re: PL/SQL vs JAVA vs C  [new]
пришел и все
Guest
Vint
автор упёрся в стенку и махал красным флагом.


Нет. Он там просто уперся и окончательно выключил мозг.
27 дек 11, 15:19    [11833616]     Ответить | Цитировать Сообщить модератору
Все форумы / Oracle Ответить