2016-08-19 2 views
0

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?

+1

Sie haben übersehen Profilierung. Siehe [PL/SQL Hierarchischer Profiler] (https://docs.oracle.com/cd/B28359_01/appdev.111/b28424/adfns_profiler.htm). – user272735

+0

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.) –

Antwort

0

Meine Vermutung wäre die mehrere Verkettungen in . (Profilieren bestätigen.)

Im Idealfall würden Sie die mitgelieferten XML-Schnittstelle Werkzeuge verwenden, anstatt Tags manuell wie folgt verketten, aber trotzdem als eine schnelle Lösung würde ich versuchen, so etwas wie dieses (nicht getestet):

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 
    k_line_feed constant varchar2(1) := case when p_line_feed then chr(10) else ' ' end; 
begin 
    p_xml_body := p_xml_body || 
     ' <Cell' || 
     case when p_merge is not null then ' ss:MergeAcross="' || p_merge || '"' end || 
     case when p_style_id is not null then ' ss:StyleID="' || p_style_id || '"' end || 
     case when p_formula is not null then ' ss:Formula="' || p_formula || '"' end || 
     '><Data ss:Type="' || p_data_type || '">' || p_content || '</Data></Cell>' || 
     k_line_feed; 
end cell_write; 
+0

Ok danke Ich werde experimentieren und sehen, was ich bekomme – Jaffa6

+0

Danke für Kommentare, ich war nicht vertraut mit DBMS Profiling, ich habe jetzt gelernt und verwendet und habe das Programm wieder auf 30 Minuten reduziert. Es scheint, dass die ständige Verknüpfung mit einem CLOB sehr ineffizient ist. – Jaffa6

0

Ein Ansatz, den ich seit langem nutze, ist die temporäre CLOBs mit einer varchar2 Stateful PL/SQL Variable als Puffer vor der Ausführung von CLOB Attends. Und ich habe eine einfache API um den Kern DBMS_LOB erstellt, um mir zu erlauben, zu mehr als einer CLOB zu jeder Zeit zu schreiben, abwechselnd zwischen ihnen wenn notwendig. Sie können einen Blick auf sie, vielleicht können Sie eine noch bessere Leistung erzielen:

https://github.com/GeraldoViana/nksg/blob/master/src/nksg_tempclob.pks https://github.com/GeraldoViana/nksg/blob/master/src/nksg_tempclob.pkb

+0

Während dieser Link die Frage beantworten kann, ist es besser, die wesentlichen Teile der Antwort hier aufzunehmen und den Link als Referenz zur Verfügung zu stellen. Nur-Link-Antworten können ungültig werden, wenn sich die verknüpfte Seite ändert. - [Aus Bewertung] (/ review/low-quality-posts/18329433) – Sree