Tworzymy korzystając z bibliotek dostarczanych od producenta kawałek kodu i okazuje się, że jest albo za wolno albo niestabilnie dla naszego zbioru danych. Czasami udaje się nam błądzić po parametrach brzegowych lub znaleźć zastosowania dla funkcji bibliotecznych o jakich się nie śniło ich autorom.
Przykładem jest nadzwyczaj nędzna wydajność operacji łańcuchowych na polach typu CLOB. Rozważmy poniższy blok kodu.
Instrukcja dbms_random.string('p', 4000) oznacza stwórz losowy łańcuch tekstowy składający się z 4000 widocznych na wydruku znaków ASCII.
Kod poniższy tworzy losowy łańcuch długości 32000 znaków i zlicza w nim cyferki dwoma metodami za pomocą zliczania naiwnego i wyrażenia regularnego reagującego na cyferki..
Celem dalszych testów przypomnijmy sobie, że w kodzie PL/SQL maksymalna wielkość zmiennej typu VARCHAR2 wynosi 32767 znaków...
DECLARE
vc_Clob CLOB := EMPTY_CLOB();
vn_Start NUMBER;
vn_Count NUMBER := 0;
vn_Size NUMBER;
BEGIN
vc_Clob :=dbms_random.string('p', 4000);
vc_Clob := vc_Clob || vc_Clob;
vc_Clob := vc_Clob || vc_Clob;
vc_Clob := vc_Clob || vc_Clob;
vn_Start := dbms_utility.get_time;
vn_Size := LENGTH(vc_Clob);
FOR lp IN 1..vn_Size
LOOP
IF SUBSTR( vc_Clob, lp, 1) BETWEEN '0' AND '9' THEN
vn_Count := vn_Count + 1;
END IF;
END LOOP;
dbms_output.put_line( 'Metoda 1. Długość : ' || LENGTH (vc_Clob) || ', liczba cyferek ' || vn_Count );
dbms_output.put_line( ROUND( (dbms_utility.get_time- vn_start)/100, 2 ) || ' sekund...' );
vn_Start := dbms_utility.get_time;
vn_Count := REGEXP_COUNT( vc_Clob,'[[:digit:]]');
dbms_output.put_line( ' Metoda 2. Długość : ' || LENGTH (vc_Clob) || ', liczba cyferek ' || vn_Count );
dbms_output.put_line( ROUND( (dbms_utility.get_time- vn_start)/100, 2 ) || ' sekund...');
END;
Po uruchomieniu na wydajnym serwerze, radzącym sobie z terabajtowymi bazami, otrzymujemy następujący wynik
Metoda 1. Długość : 32000, liczba cyferek 3224
8.8 sekund...
Metoda 2. Długość : 32000, liczba cyferek 3224
0.1 sekund...
Różnica jest olbrzymia - ale oba rozwiązania są wolne..
Zamieńmy w powyższym bloku linię
vc_Clob CLOB := EMPTY_CLOB();
na
vc_Clob VARCHAR(32000 CHAR);szybko okażesię ,że nawet grudniowe noce sa za krótkie
Wówczas otrzymamy następujące czasy wykonania:
Metoda 1. Długość : 32000, liczba cyferek 3424
0.01 sekund...
Metoda 2. Długość : 32000, liczba cyferek 3424
0.16 sekund...
Dla metody naiwnej przyrost wydajności jest prawie tysiąckrotny, wyrażenia regularne dla obu typów działają wolno z podobną szybkością..
Co więc robić jeśli chcemy napisać zaawansowane przetwarzanie obszernych pól CLOB??
- przenieść procesowanie na godziny nocne, szybko okaże się, że nawet grudniowe noce są za krótkie
- napisać to przetwarzanie w Java/C++ na kliencie na jakimś złomowatym serwerze. I tak będzie szybciej:)
- postarać się tak zmienić strukturę danych, aby korzystać tylko z typów VARCHAR2, co nie zawsze jest wykonalne