![]() |
Технология Клиент-Сервер 2009'1 |
||||||
|
Native compilation – это не совсем новая возможность, однако теперь нет «узких» мест её использования, таких, например, как установка компилятора C (Oracle назвал эту замечательную возможность "Real Native Compilation"). Кроме того, новый тип данных simple_integer при Native compilation увеличивает производительность кода. Intra-unit inlining – это техника оптимизации, применяемая к PL/SQL-коду во время компиляции для повышения эффективности кода. В данной статье будут рассмотрены некоторые случаи использования этих новых возможностей. Будет также проверена их производительность при различных сценариях: при использовании Native compilation, типа simple_integer, Intra-unit inlining и их различных комбинаций.
Вспомните Native compilation в Oracle9i Database Release 2; она существенно ускоряла выполнение PL/SQL-программ по сравнению с интерпретируемыми формами. С другой стороны, освоение было медленным, так как многие системные администраторы сопротивлялись установке необходимого компилятора C на производственный сервер БД. Кроме того, такие компиляторы требуют установки параметра plsql_native_library_dir с директорией для промежуточных файлов OС. В Oracle Database 11g можно выполнять Native compilation без компилятора C на сервере и без установки упомянутого параметра. Всё, что необходимо сделать, это установить параметр сессии перед созданием или перекомпиляцией хранимого кода:
alter session set plsql_code_type = native; ... здесь выполняется компиляция ... |
Native compilation выполняется дольше, чем interpreted compilation, но поскольку сам этот процесс в Oracle Database 11g намного быстрее, то разница может оказаться незаметной. Лучше всего применять interpreted compilation во время обычного цикла разработки и Native compilation, когда разработка завершена.
Как часть миграции на 11g, я выполнил эксперимент с реальным кодом из диагностического приложения над очень большим пакетом из 5 827 строк. Я скомпилировал его в режиме Native compilation на существующей базе данных 10g и сделал то же самое на 11g, а затем повторил эти действия в режиме interpreted compilation. Каждая из этих компиляций была выполнена с параметром plsql_optimize_level, равным 2. Я измерил время компиляции для каждого случая, оно показано ниже (в секундах).
10g |
11g |
|
---|---|---|
Interpreted |
1.66 |
1.64 |
Native |
4.66 |
2.81 |
Результаты говорят сами за себя. При interpreted compilation время компиляции почти одинаковое. Однако при Native compilation время компиляции в Oracle 11g меньше примерно на 60% по сравнению с версией 10g, а это существенное улучшение. Итак, хотя Native compilation в 11g требует дополнительного времени, она намного быстрее, чем Native compilation в 10g.
Чтобы найти объекты, скомпилированные с помощью NATIVE, смотрите представление USER_PLSQL_OBJECT_SETTINGS:
SQL> select name, PLSQL_code_type 2> from user_plsql_object_settings; NAME PLSQL_CODE_TYPE -------------------- --------------- DO_CALC NATIVE PERFECT_TRIANGLES NATIVE PRIME_NUMBERS NATIVE PRIME_NUMBERS NATIVE SOME_MATH INTERPRETED TR_BOOKINGS_TRACK INTERPRETED TR_SALGRADE_COMP INTERPRETED UPD_INT NATIVE |
Есть и похожее представление для всех объектов, DBA_PLSQL_OBJECT_SETTINGS.
Достоинства Native compilation ещё более очевидны при использовании нового типа данных, simple_integer. Технически это не настоящий тип данных, а скорее подтип pls_integer. Этот подтип создан для улучшения машинных вычислений по сравнению с программными вычислениями. Когда simple_integer используется одновременно с Native compilation, производительность будет намного лучше. В эксперименте, который будет показан дальше, вы увидите, почему.
Так как simple_integer является подтипом pls_integer, он наследует его свойства как 32-битного целого числа со знаком и может быть целым числом от -2,147,483,648 до 2,147,483,647. Однако он отличается от pls_integer следующим: он не допускает значения null, но допускает переполнение — когда значение превышает максимум, оно сбрасывается, а ошибка не появляется.
Этот тип данных можно синтаксически использовать во всех тех же местах, где и pls_integer, но необходимо внимательно следить за разницей; дополнительные свойства simple_integer в некоторых случаях могут оказаться неуместными.
Давайте проверим несколько потенциальных задач, где следовало бы заменить pls_integer на simple_integer:
num1 simple_integer:= 1; |
а написать так:
num1 simple_integer; |
то будет получена ошибка компиляции:
PLS-00218: a variable declared NOT NULL must have an initialization assignment |
Если установить значение переменной в NULL внутри программы, например, так:
num1 := NULL; |
будет получена ошибка компиляции:
PLS-00382: expression is of wrong type |
Избегайте этих сообщений об ошибках, которые могут не отражать точной сути ошибки. Если программа ожидает установки переменной в null, то не следует описывать переменную, как simple_integer.
declare v1 pls_integer := 2147483647; begin v1 := v1 + 1; dbms_output.put_line('v1='||v1); end; / |
Будет получена ошибка:
declare
*
ERROR at line 1:
ORA-01426: numeric overflow
ORA-06512: at line 4
|
Ошибка очевидна и вполне уместна; вы попытались превысить максимальное значение, допустимое для типа данных. Если вместо pls_integer использовать simple_integer:
declare v1 simple_integer := 2147483647; begin v1 := v1 + 1; dbms_output.put_line('v1='||v1); end; / |
Результат будет следующим:
v1=-2147483648 |
Заметьте, что значение (-2147483648), это минимальное значение simple_integer. Когда вы прибавляете к максимальному значению (2147483647), значение просто сбрасывается до минимального — это особенность simple_integer. Помните об этом поведении.
Как видите, simple_integer не могут использоваться в любом месте; при использовании этого типа необходимо внимательно учитывать дополнительные условия (особенно возможный сброс значений). Поэтому simple_integer создан для Native compilation. В режиме interpreted compilation эффекта производительности может не быть (но и вреда нет, как будет показано дальше). В режиме Native compilation выигрыш в производительности от использования simple_integer намного существеннее.
Большинство бизнес-приложений на PL/SQL жестко связаны с SQL, поэтому эти приложения не увидят значительного изменения производительности при Native compilation. В "прошлой жизни " я разрабатывал инструмент для планирования базы данных с использованием PL/SQL, включающего много числовых и статистических вычислений в несколько тысяч строк кода. При Native compilation было видно существенное увеличение в производительности. Числа типа Simple_integer не были доступны в то время, но если бы были, то они добавили бы производительности.
Intra-unit inlining представляет собой подмену вызова подпрограммы на копию кода этой подпрограммы. В результате модифицированный код выполняется быстрее. В Oracle Database 11g компилятор PL/SQL способен идентифицировать вызовы подпрограммы, которую необходимо скопировать (другими словами, подменить на неё) и вносит изменения, повышающие производительность.
Лучше всего это объяснить на примере. Код, показанный ниже, изменяет таблицу BALANCES, вычислив значения на основании баланса счёта. Код проходит по всем записям таблицы, вычисляет результат, и изменяет столбец таблицы с балансом.
create or replace procedure upd_int is /* original version */ l_rate_type balances.rate_type%type; l_bal balances.balance%type; l_accno balances.accno%type; l_int_rate number; procedure calc_int ( p_bal in out balances.balance%type, p_rate in number ) is begin if (p_rate >= 0) then p_bal := p_bal * (1+(p_rate/12/100)); end if; end; begin for ctr in 1..10000 loop l_accno := ctr; select balance, rate_type into l_bal, l_rate_type from balances where accno = l_accno; select decode(l_rate_type, 'C', 1, 'S', 3, 'M', 5, 0) into l_int_rate from dual; for mth in 1..12 loop calc_int (l_bal, l_int_rate); update balances set balance = l_bal where accno = l_accno; end loop; end loop; end; / |
Фактически, вычисление результата одинаково для всех типов записей, и я поместил логику в отдельную процедуру calc_int() внутри основной процедуры. Это повышает читаемость и сопровождаемость кода, но, к сожалению, это неэффективно.
Однако если заменить вызов calc_int() на код calc_int(), получится более быстрая программа, как показано ниже:
create or replace procedure upd_int is /* revised version */ l_rate_type balances.rate_type%type; l_bal balances.balance%type; l_accno balances.accno%type; l_int_rate number; begin for ctr in 1..10000 loop l_accno := ctr; select balance, rate_type into l_bal, l_rate_type from balances where accno = l_accno; select decode(l_rate_type, 'C', 1, 'S', 3, 'M', 5, 0) into l_int_rate from dual; for mth in 1..12 loop -- this is the int calc routine if (l_int_rate >= 0) then l_bal := l_bal * (1+(l_int_rate/12/100)); end if; update balances set balance = l_bal where accno = l_accno; end loop; end loop; end; / |
Этот переделанный код отличается от исходного только в части кода для вычисления баланса, который теперь внутри цикла, а не в процедуре calc_int().
Заметьте, что новая версия может быть быстрее, но это пример не очень хорошей практики кодирования. Часть кода, выполняющая вычисление баланса, выполняется один раз для каждой итерации цикла для месяцев, а затем и для каждого номера счёта. Так как эта часть кода повторяется, она более удобна для размещения отдельно, как показано в предыдущей версии upd_int, в процедуре (calc_int). Этот подход делает код модульным, легким в поддержке, и реально читаемым — но также менее эффективным.
Поэтому как можно достичь примирения конфликтующих способов создания кода, сделав код модульным и одновременно быстрым? Так, а можно ли написать код, используя модульный подход (как в первой версии upd_int), а затем позволить компилятору PL/SQL "оптимизировать" его, чтобы он стал выглядеть, как во второй версии кода?
Это можно сделать в Oracle Database 11g. Всё, что требуется сделать – перекомпилировать процедуру с более высоким уровнем оптимизации PL/SQL. Этого можно достичь двумя способами:
SQL> alter session set plsql_optimize_level = 3; Session altered. |
Команда, показанная выше, инструктирует компилятор PL/SQL, чтобы он переписал код во встроенный код.
SQL> alter procedure upd_int 2 compile 3 plsql_optimize_level = 3 4 reuse settings; Procedure altered. |
На любую другую процедуру, компилируемую в этой же сессии, это не повлияет. Этот метод лучше применять для обработки inlining, если есть много процедур, которые необходимо скомпилировать в одной сессии.
Можно также использовать директиву компилятора pragma:
create or replace procedure upd_int is l_rate_type varchar2(1); ... ... begin pragma inline (calc_int, 'YES'); for ctr in 1..10000 loop ... ... end; |
Я добавил строку pragma inline (calc_int, 'YES'); для указания компилятору подменить в коде эту процедуру. Таким же образом можно указать "NO" в этом же месте, чтобы передать компилятору, что не надо подменять эту процедуру, даже если plsql_optimizer_level установлен в значение 3.
Inlining ускоряет выполнение кода. Точная степень улучшения будет зависеть, конечно же, от количества подмен, которые будут сделаны компилятором. В конце этой статьи мы рассмотрим пример с использованием inlining и увидим улучшение производительности в результате его применения.
Конечно, этот процесс оптимизации затрудняет работу компилятора. Но насколько?
Чтобы ответить на этот вопрос, я взял код реального приложения, показанный выше, и скомпилировал его в различных комбинациях с inlining/без inlining и interpreted/native. Вот время компиляции:
Inlined |
Not inlined |
|
---|---|---|
Interpreted |
1.70 |
1.64 |
Native |
3.15 |
2.81 |
Результаты говорят сами за себя. При компиляции с использованием inline, время компиляции выше совсем чуть-чуть (около 4%) в режиме interpreted. В режиме native, оно выше, но и разница больше — около 12%. Таким образом, целесообразно компилировать приложение в режиме inline/interpreted во время разработки, а затем в режиме native на стадии окончания. Использование inlining несущественно увеличивает время компиляции, при разработке такое увеличение несущественно.
Теперь мы подошли к важному вопросу: Раз код не менялся, как можно подтвердить, что код был подменён? Это можно сделать с помощью переменной сессии:
alter session set plsql_warnings = 'enable:all'; |
Теперь, после пересоздания процедуры:
SQL> @upd_int SP2-0804: Procedure created with compilation warnings |
Обратите внимание на последнюю строку. Эта строка подтверждает, что процедура calc_int была подменена.
SQL> show error Errors for PROCEDURE UPD_INT: LINE/COL ERROR -------- ----------------------------------------------------------------- 7/5 PLW-06006: uncalled procedure "CALC_INT" is removed. 28/13 PLW-06005: inlining of call of procedure 'CALC_INT' was done |
Если вы хотите найти объекты, которые были скомпилированы с этим уровнем оптимизации, можно выполнить запрос к представлению USER_PLSQL_OBJECT_SETTINGS:
sql> select name, plsql_optimize_level 2> from user_plsql_object_settings; NAME PLSQL_OPTIMIZE_LEVEL -------------------- -------------------- DO_CALC 2 PERFECT_TRIANGLES 2 TR_BOOKINGS_TRACK 2 TR_SALGRADE_COMP 2 UPD_INT 3 ... и так далее ... |
Есть и похожее представление для всех объектов: DBA_PLSQL_OBJECT_SETTINGS.
Помните, intra-unit inlining означает, что подменяются только те процедуры, которые расположены внутри блока. Внешние подпрограммы не подменяются.
Теперь настало время проверить эти достоинства экспериментально. Создадим базовую версию пакета, а затем модифицируем тип данных переменных и директивы компилятора в соответствии с концепциями, изученными перед этим.
Сначала реализуем алгоритм Евклида для поиска наибольшего общего делителя для двух чисел. Вот логика функции, со страницы Wiki:
function gcd(a, b) if a = 0 return b while b ? 0 if a > b a := a - b else b := b - a return a |
Замерим процессорное время выполнения пакета при различных комбинациях этих модификаций и сохраним затраченное время. Итак, создаём таблицу для сохранения процессорного времени:
create table times( native char(1) check (native in ('Y', 'N')) enable, simple char(1) check (simple in ('Y', 'N')) enable, inlining char(1) check (inlining in ('Y', 'N')) enable, centiseconds number not null, constraint times_pk primary key (simple, inlining, native)) / |
Создадим три столбца — native, simple и inlining — для обозначения Native compilation, чисел типа simple_integer, и inlined-кода, соответственно. "Y" в столбце означает, что код скомпилирован с использованием этой возможности. Итак, получается запись, которая выглядит следующим образом:
NATIVE SIMPLE INLINING CENTISECONDS ------ ------ -------- ------------ Y N N 100 |
Она показывает, что программа была скомпилирована в режиме Native compilation, но числа типа simple_integer не использовались, inlining не применялось, и что эта компиляция заняла 100 сёнтисекунд процессорного времени.
Чтобы использовать только одну копию пакета, для модификации пакета применим условную компиляцию (появилась в Oracle Database 10g Release 2). Ниже показано, как создать пакет:
-- подавляем следующие ожидаемые предупреждения: -- inlining of call of procedure 'gcd' was done -- uncalled procedure "gcd" is removed. -- unreachable code -- keyword "native" used as a defined name alter session set plsql_warnings = 'enable:all, disable:06002, disable:06005, disable:06006, disable:06010' / alter session set plsql_ccflags = 'simple:false' / create package gcd_test is procedure time_it; end gcd_test; / create package body gcd_test is $if $$simple $then subtype my_integer is simple_integer; simple constant times.simple%type := 'y'; $else subtype my_integer is pls_integer not null; simple constant times.simple%type := 'n'; $end function gcd(p1 in my_integer, p2 in my_integer) return my_integer is v1 my_integer := p1; v2 my_integer := p2; begin while v2 > 0 loop if v1 > v2 then v1 := v1 - v2; else v2 := v2 - v1; end if; end loop; return v1; end gcd; function exercise_gcd return number is -- ожидается значение, зависящее от no_of_iterations. expected_checksum my_integer := 74069926; -- 2475190; no_of_iterations constant my_integer := 5000; -- 1000; checksum my_integer := 0; v my_integer := 0; t0 number; t1 number; begin for warmup in 1..2 loop checksum := 0; t0 := dbms_utility.get_cpu_time(); for j in 1..no_of_iterations loop v := gcd(j, j); if v <> j then raise_application_error(-20000, 'logic error: gcd(j, j) <> j'); end if; checksum := checksum + v; for k in (j + 1)..no_of_iterations loop v := gcd(j, k); if gcd(k, j) <> v then raise_application_error( -20000, 'logic error: gcd(j, k) <> gcd(k, j)'); end if; checksum := checksum + v; end loop; end loop; if checksum <> expected_checksum then raise_application_error( -20000, 'checksum <> expected_checksum: '||checksum); end if; t1 := dbms_utility.get_cpu_time(); end loop; return t1 - t0; end exercise_gcd; procedure time_it is inlining times.inlining%type; native times.native%type; centiseconds constant times.centiseconds%type := exercise_gcd(); begin if lower($$plsql_code_type) = 'native' then native := 'y'; else native := 'n'; end if; if $$plsql_optimize_level = 3 then inlining := 'y'; else inlining := 'n'; end if; insert into times(native, simple, inlining, centiseconds) values( time_it.native, gcd_test.simple, time_it.inlining, time_it.centiseconds); commit; end time_it; end gcd_test; / show errors |
Пакет имеет достаточно однострочных комментариев для самодокументации кода, поэтому здесь подробные объяснения не требуются. А в общем, функция GCD() имеет два входных параметра и возвращает наибольший общий делитель. Функция exercise_gcd() вызывает функцию GCD() и возвращает время работы процессора (CPU time) в сотых долях секунды. Наконец, public-процедура TIME_IT() вызывает функцию EXERCISE_GCD() и вставляет запись в таблицу TIMES.
Теперь надо несколько раз вызвать пакетную процедуру с различными параметрами и зафиксировать время работы процессора в каждом случае. Выполним это, изменив переменные условной компиляции перед тем, как компилировать пакет:
truncate table times / -- Interpreted --------------------------------------------- -- Simple:false -- No Inlining alter package GCD_Test compile body PLSQL_Code_Type = interpreted PLSQL_CCFlags = 'Simple:false' PLSQL_Optimize_Level = 2 /* no inlining */ reuse settings / begin GCD_Test.Time_It(); end; / -- inlining alter package GCD_Test compile body PLSQL_Code_Type = interpreted PLSQL_CCFlags = 'Simple:false' PLSQL_Optimize_Level = 3 /* inlined */ reuse settings / begin GCD_Test.Time_It(); end; / -- Числа типа simple_integer: используются -- Без inlining alter package GCD_Test compile body PLSQL_Code_Type = interpreted PLSQL_CCFlags = 'Simple:true' PLSQL_Optimize_Level = 2 reuse settings / begin GCD_Test.Time_It(); end; / -- inlined alter package GCD_Test compile body PLSQL_Code_Type = interpreted PLSQL_CCFlags = 'Simple:true' PLSQL_Optimize_Level = 3 reuse settings / begin GCD_Test.Time_It(); end; / -- Native ------------------------------------------------- -- Числа типа simple_integer: не используются -- Без inlining alter package GCD_Test compile body PLSQL_Code_Type = native PLSQL_CCFlags = 'Simple:false' PLSQL_Optimize_Level = 2 reuse settings / begin GCD_Test.Time_It(); end; / -- inlined alter package GCD_Test compile body PLSQL_Code_Type = native PLSQL_CCFlags = 'Simple:false' PLSQL_Optimize_Level = 3 reuse settings / begin GCD_Test.Time_It(); end; / -- Числа типа simple_integer: используются -- Без linlining alter package GCD_Test compile body PLSQL_Code_Type = native PLSQL_CCFlags = 'Simple:true' PLSQL_Optimize_Level = 2 reuse settings / begin GCD_Test.Time_It(); end; / -- inlined alter package GCD_Test compile body PLSQL_Code_Type = native PLSQL_CCFlags = 'Simple:true' PLSQL_Optimize_Level = 3 reuse settings / begin GCD_Test.Time_It(); end; / |
Для определения, насколько повышается производительность при каждом из этих сценариев, используем следующий код:
spool timings.txt <<b>>declare Interp_Pls_Integer_Noinline Times.Centiseconds%type; Interp_Pls_Integer_Inline Times.Centiseconds%type; Interp_Simple_Integer_Noinline Times.Centiseconds%type; Interp_Simple_Integer_Inline Times.Centiseconds%type; Native_Pls_Integer_Noinline Times.Centiseconds%type; Native_Pls_Integer_Inline Times.Centiseconds%type; Native_Simple_Integer_Noinline Times.Centiseconds%type; Native_Simple_Integer_Inline Times.Centiseconds%type; procedure Show_Caption(Caption in varchar2) is begin DBMS_Output.Put_Line( Chr(10)||Rpad('-', 60, '-')||Chr(10)||Chr(10)||Caption||Chr(10)); end Show_Caption; procedure Show_Ratio(Var1 in varchar2, Var2 in varchar2, Ratio in number) is begin DBMS_Output.Put_Line(Rpad( Var1, 15)||'and '||Rpad(Var2, 14)||To_Char(Ratio, '99.99')); end Show_Ratio; begin select a.Centiseconds into b.Interp_Pls_Integer_Noinline from Times a where a.Native = 'N' and a.Simple = 'N' and a.Inlining = 'N'; select a.Centiseconds into b.Interp_Pls_Integer_Inline from Times a where a.Native = 'N' and a.Simple = 'N' and a.Inlining = 'Y'; select a.Centiseconds into b.Interp_Simple_Integer_Noinline from Times a where a.Native = 'N' and a.Simple = 'Y' and a.Inlining = 'N'; select a.Centiseconds into b.Interp_Simple_Integer_Inline from Times a where a.Native = 'N' and a.Simple = 'Y' and a.Inlining = 'Y'; select a.Centiseconds into b.Native_Pls_Integer_Noinline from Times a where a.Native = 'Y' and a.Simple = 'N' and a.Inlining = 'N'; select a.Centiseconds into b.Native_Pls_Integer_Inline from Times a where a.Native = 'Y' and a.Simple = 'N' and a.Inlining = 'Y'; select a.Centiseconds into b.Native_Simple_Integer_Noinline from Times a where a.Native = 'Y' and a.Simple = 'Y' and a.Inlining = 'N'; select a.Centiseconds into b.Native_Simple_Integer_Inline from Times a where a.Native = 'Y' and a.Simple = 'Y' and a.Inlining = 'Y'; Show_Caption(' Преимущества simple_integer '); Show_Ratio(' Интерпретирующая ', 'no inlining', Interp_Pls_Integer_Noinline / Interp_Simple_Integer_Noinline); Show_Ratio(' Интерпретирующая ', 'inlining', Interp_Pls_Integer_Inline / Interp_Simple_Integer_Inline); Show_Ratio('Native', 'no inlining', Native_Pls_Integer_Noinline / Native_Simple_Integer_Noinline); Show_Ratio('Native', 'inlining', Native_Pls_Integer_Inline / Native_Simple_Integer_Inline); Show_Caption(' Преимущества inlining '); Show_Ratio(' Интерпретирующая ', 'pls_integer', Interp_Pls_Integer_Noinline / Interp_Pls_Integer_Inline); Show_Ratio(' Интерпретирующая ', 'simple_integer', Interp_Simple_Integer_Noinline / Interp_Simple_Integer_Inline); Show_Ratio('Native', 'pls_integer', Native_Pls_Integer_Noinline / Native_Pls_Integer_Inline); Show_Ratio('Native', 'simple_integer', Native_Simple_Integer_NoInline / Native_Simple_Integer_Inline); Show_Caption(' Преимущества Native compilation '); Show_Ratio('pls_integer', 'no inlining', Interp_Pls_Integer_Noinline / Native_Pls_Integer_Noinline); Show_Ratio('pls_integer', 'inlining', Interp_Pls_Integer_Inline / Native_Pls_Integer_Inline); Show_Ratio('simple_integer', 'no inlining', Interp_Simple_Integer_Noinline / Native_Simple_Integer_Noinline); Show_Ratio('simple_integer', 'inlining', Interp_Simple_Integer_Inline / Native_Simple_Integer_Inline); end b; / spool off |
Ниже показан результат. Он показывает рейтинг процессорного времени по сравнению со значением по умолчанию: без inlining, interpreted compilation, и использование pls_integer.
------------------------------------------------------------ Преимущества simple_integer Интерпретирующая и без inlining 1.00 Интерпретирующая и c inlining 1.00 Native и без inlining 2.19 Native и с inlining 2.79 ------------------------------------------------------------ Преимущества inlining Интерпретирующая и pls_integer 1.07 Интерпретирующая и simple_integer 1.07 Native и pls_integer 1.16 Native и simple_integer 1.48 ------------------------------------------------------------ Преимущества Native compilation pls_integer и без inlining 4.78 pls_integer и inlining 5.18 simple_integer и без inlining 10.53 simple_integer и inlining 14.49 |
Из показанных выше результатов видно, что процессорное время, потраченное на выполнение, было 14.49 для значения по умолчанию по сравнению с Native compilation с inlining и simple_integer — очень впечатляющий выигрыш по любым меркам.
Теперь вы можете оценить важность и полезность этих новых возможностей. Итог:
![]() |
Технология Клиент-Сервер 2009'1 |
||||||
|
![]() |
Технология Клиент-Сервер 2009'1 |
||||||
|
Корпорация Oracle опубликовала результаты III квартала 2009 финансового года. Совокупный доход (по GAAP) вырос на 2% и составил 5,5 млрд. долларов, в то время как чистая прибыль сократилась на 1% до 1,3 млрд. долларов.
Доходы от программного обеспечения выросли на 5% и составили 4,4 млрд. долларов, включая доходы от продажи лицензий, которые составили 1,5 млрд. долларов (что на 6% ниже, чем в третьем квартале прошлого года). При этом продажи лицензий на бизнес-приложения упали на 12% до 396 млн. долларов, а продажи лицензий на СУБД и промежуточное ПО понизились на 3% и составили 1,12 млрд. долларов.
Доходы от оказания услуг снизились на 8% до 1 млрд. долларов. Обновление и сопровождение программных продуктов принесло разработчику 2,9 млрд. долларов, т.е. на 11% больше, чем год назад. Это направление деятельности обеспечило Oracle более половины доходов за квартал.
Комментируя финансовые итоги третьего квартала, Ларри Эллисон (Larry Ellison), CEO Oracle, назвал их большим достижением в условиях серьезного спада в мировой экономике. По утверждению руководства Oracle, на не слишком позитивные результаты существенно повлияли невыгодные для компании курсы валют. По словам Чарльза Филлипса (Charles Phillips), президента Oracle, без учета влияния валютных курсов доходы Oracle от продажи лицензий на ПО в завершившемся квартале превысили бы результаты аналогичного периода прошлого года.
Представляя финансовые результаты компании г-н Эллисон подтвердил, что разработку нового поколения бизнес-приложений Fusion Applications планируется завершить к 2010 году.
![]() |
Технология Клиент-Сервер 2009'1 |
||||||
|
![]() |
Технология Клиент-Сервер 2009'1 |
||||||
|
Корпорация Oracle выпустила новую версию Oracle Enterprise Manager, включающую расширенные средства управления для Oracle WebLogic Server и других компонентов Oracle Fusion Middleware.
Компаниям, использующим Oracle WebLogic Server, теперь предоставляется единое решение для управления приложениями, исключающее потребность в применении множества инструментов. Компании, планирующие развернуть этот сервер приложений и использующие Oracle Application Server, теперь могут применять привычный набор инструментов в Oracle Enterprise Manager для ускоренного внедрения Oracle WebLogic Server.
Кроме того, Oracle Enterprise Manager 10gR5 включает решение Composite Application Monitor and Modeler for SOA для управления производительностью приложений на базе моделей, новые средства управления для Oracle Service Bus, Oracle Coherence и Oracle Beehive, а также более совершенные функции управления для Oracle BPEL Process Manager.
![]() |
Технология Клиент-Сервер 2009'1 |
||||||
|
Copyright © 1994-2016 ООО "К-Пресс"