Całość eksperymentów przeprowadziłem na Oracle 11g 64 bit zainstalowanym na Windows 7.
Napisałem niezwykle prostą funkcję w C
int _stdcall sum(int x , int y)
{
return x+y;
}
Korzystając z kompilatora Microsoft Visual C++ opakowałem powyższą w bibliotekę DLL na platformę x64( 32 bitowe biblioteki nie współdziałają z Oracle 64 bit), wygenerowałem plik test_dll.dll.
Kilka chwil zajęło zmuszenie listenera do współpracy, ale przy odrobinie dobrych chęci nie jest to trudne. Natępnie podłączyłem zewnętrzny kod:
CREATE OR REPLACE LIBRARY MyC_LIB
AS 'D:\Projects\CPP\test_dll\Release\test_dll.dll';
CREATE OR REPLACE FUNCTION test_CSUM
(x BINARY_INTEGER, y BINARY_INTEGER
RETURN BINARY_INTEGER
AS LANGUAGE C
LIBRARY MyC_LIB
NAME "sum";
Następnie wykonałem zapytanie:
SELECT SUM(TEST_CSUM(2,1)) /3 FROM ALL_TAB_COLS
Wynik z zapytania zwraca liczę rekordów z view: wynik 90451 rekordów został otrzymany w czasie 30 sekund. Wychodzi około 3 tysięcy wywołań rekordów na sekundę ..
Pokombinujmy, jeśli do definicji funkcji dodamy modyfikator DETERMINISTIC , to czas wykonania spadnie do 1s. Ale:
- funkcje deterministyczne to szczególny przypadek i dosyć rzadki w przyrodzie
- funkcje deterministyczne warto stosować, jeśli zbiór parametrów wejściowych jest niewielki, dla obliczeń numerycznych dla co najwyżej kilkunastotysięcznego zbioru parametrów wejściowych
- Oracle w przypadku zewnętrznych procedur nie zwróci nam uwagi, że wynik funkcji zależy od daty lub generatora liczb losowych
Mogłoby się wydawać, że natywne niskopoziomowe biblioteki DLL powinny być niezwykle szybkie, a jednak nie nadają się do wykorzystania w przypadku zapytań obrabiających duże zbiory danych...
Wykonajmy analogiczny eksperyment z Java...
public class SumTest {public static int sum (int a, int b)
{
return a+b;
}
}
Załadujmy klasę:
loadjava -thin -user user/pwd@test d:\PLSQL\SumTest.java
Dla Oracle 64 bit dla Windows loadjava działa tylko w wersji thin..
Kompilujemy pakiet i mapujemy funkcję
alter java class user."SumTest" compile;
CREATE OR REPLACE FUNCTION user.test_jsum
(a NUMBER, b Number)
RETURN NUMBER
AS
LANGUAGE JAVA
NAME 'SumTest.sum
(int, int) return int';
I sprawdzenie
SELECT SUM(TEST_JSUM(2,1)) /3 FROM ALL_TAB_COLS
Wynik 90451 rekordów pojawił się po 5 sekundach.. Jest pięć razy szybciej około 18 tysięcy rekordów na sekundę.. Dla niewielkich zbiorów danych można ścierpieć...
Podsumowując: do przetwarzanie masowego wielkich zbiorów danych funkcje zewnętrzne się nie nadają.. Najlepiej sprawdzają się w rzadkich i nieczęsto stosowanych przypadkach
Brak komentarzy:
Prześlij komentarz