Ich habe PL/SQL-Programm, das nach einigen Änderungen von einer Laufzeit von 30 Minuten auf 3 Stunden gegangen ist, konnten wir nicht feststellen, wie die Leistung verbessert werden kann. Das Programm gab ursprünglich eine CSV-Datei zur Verwendung in Excel aus. Das Programm wurde nun dahingehend geändert, dass XML zur Verwendung in Excel ausgegeben wird. So gab es keine Codeänderungen in Bezug auf SQL oder Datenbanklesevorgänge. Die relevanten Code-Additionen sind Prozeduren, die aus einem zugeordneten Paket abgerufen werden, das Clobs erstellt, die dann regelmäßig in die Datei ausgegeben werden, um so eine übermäßige Speichernutzung zu vermeiden. Die Anzahl der utl_file.put_line-Verwendungen ist in beiden Versionen des Programms ähnlich.PL/SQL CPU-Leistungsoptimierung
Ein Beispiel des Codes verwendet wird, die CLOB- zu bauen
PROCEDURE cell_write(p_xml_body IN OUT NOCOPY CLOB,
p_data_type IN VARCHAR2 := 'String',
p_style_id IN VARCHAR2 := NULL,
p_merge IN VARCHAR2 := NULL,
p_formula IN VARCHAR2 := NULL,
p_line_feed IN BOOLEAN := TRUE,
p_content IN VARCHAR2) IS
v_line_feed VARCHAR2(01) ;
BEGIN
IF p_line_feed
THEN
v_line_feed := chr(10) ;
ELSE
v_line_feed := ' ' ;
END IF ;
p_xml_body := p_xml_body || ' <Cell';
IF p_merge IS NULL
THEN
p_xml_body := p_xml_body ;
ELSE
p_xml_body := p_xml_body || ' ss:MergeAcross="' || p_merge || '"' ;
END IF ;
IF p_style_id IS NULL
THEN
p_xml_body := p_xml_body ;
ELSE
p_xml_body := p_xml_body || ' ss:StyleID="'||p_style_id||'"' ;
END IF;
IF p_formula IS NULL
THEN
p_xml_body := p_xml_body ;
ELSE
p_xml_body := p_xml_body || ' ss:Formula="'||p_formula||'"' ;
END IF;
p_xml_body := p_xml_body || '><Data ss:Type="'||p_data_type||'">' || P_content || '</Data></Cell>' || v_line_feed;
END cell_write;
Der Codeausgabe
PROCEDURE write_file(p_filename IN VARCHAR2,
p_dir IN VARCHAR2,
p_file_handle IN utl_file.file_type,
p_clob IN CLOB)
IS
c_amount CONSTANT BINARY_INTEGER := 32767;
l_buffer VARCHAR2(32767);
l_chr10 PLS_INTEGER;
l_cloblen PLS_INTEGER;
l_fhandler utl_file.file_type;
l_pos PLS_INTEGER := 1;
BEGIN
l_cloblen := dbms_lob.getlength(p_clob);
WHILE l_pos < l_cloblen
LOOP
l_buffer := dbms_lob.substr(p_clob, c_amount, l_pos);
EXIT WHEN l_buffer IS NULL;
l_chr10 := instr(l_buffer, chr(10), -1);
IF l_chr10 != 0 THEN
l_buffer := substr(l_buffer, 1, l_chr10 - 1);
END IF;
DBMS_OUTPUT.PUT_LINE('Buffer Length ' || LENGTH(l_buffer)) ;
DBMS_OUTPUT.PUT_LINE(l_buffer) ;
utl_file.put_line(p_file_handle, l_buffer, TRUE);
l_pos := l_pos + least(length(l_buffer) + 1, c_amount);
END LOOP;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Buffer Length ' || LENGTH(l_buffer)) ;
DBMS_OUTPUT.PUT_LINE(l_buffer) ;
IF utl_file.is_open(l_fhandler) THEN
utl_file.fclose(l_fhandler);
END IF;
RAISE;
END;
und eine Probe Anruf
pk_create_excel_workbook.cell_write(p_xml_body =>v_clob_term,
p_line_feed => FALSE,
p_data_type =>'Number',
p_style_id =>'s94',
p_content =>w_totemployeecontribT);
Das Verfahren cell_write ist, zu schreiben etwa 100 Mal pro Ausgangsleitung aufgerufen und dort etwa 30.000 Ausgangsleitungen. Ausgangszeilen sind typischerweise 8000 bis 10000 Bytes lang.
Wir erwarteten eine bescheidene Steigerung der Laufzeit, aber nicht den massiven Sprung, der aufgetreten ist. Was habe ich übersehen?
Sie haben übersehen Profilierung. Siehe [PL/SQL Hierarchischer Profiler] (https://docs.oracle.com/cd/B28359_01/appdev.111/b28424/adfns_profiler.htm). – user272735
Selbst der einfache alte 'dbms_profiler' würde mit all seinen Einschränkungen anzeigen, welche Zeile die Zeit braucht, ohne auf den Server zugreifen zu müssen. Ich nehme an, es sind die Mehrfachverkettungen in 'cell_write' (die wahrscheinlich mit' case'-Anweisungen kombiniert werden können), oder aber entweder den clob lesen oder in die Datei schreiben. (Ich bin verwirrt von all diesen 'p_xml_body: = p_xml_body;' Zeilen auch.) –