Increase performance on insert cursor?

2019-09-09 11:32发布

问题:

I would like to ask you how would you increase the performance on Insert cursor in this code? I need to use dynamic plsql to fetch data but dont know how to improve the INSERT in best way. like Bulk Insert maybe? Please let me know with code example if possible.

// This is how i use cur_handle:

    cur_HANDLE integer;
cur_HANDLE := dbms_sql.open_cursor;
DBMS_SQL.PARSE(cur_HANDLE, W_STMT, DBMS_SQL.NATIVE);
DBMS_SQL.DESCRIBE_COLUMNS2(cur_HANDLE, W_NO_OF_COLS, W_DESC_TAB);

LOOP
-- Fetch a row   
IF DBMS_SQL.FETCH_ROWS(cur_HANDLE) > 0 THEN
    DBMS_SQL.column_value(cur_HANDLE, 9, cont_ID); 
    DBMS_SQL.COLUMN_VALUE(cur_HANDLE, 3, proj_NR);    
ELSE
    EXIT;
END IF;

  Insert into w_Contracts values(counter, cont_ID, proj_NR);
counter := counter + 1;
END LOOP;

回答1:

You should do database actions in sets whenever possible, rather than row-by-row inserts. You don't tell us what CUR_HANDLE is, so I can't really rewrite this, but you should probably do something like:

INSERT INTO w_contracts
SELECT ROWNUM, cont_id, proj_nr
  FROM ( ... some table or joined tables or whatever... )

Though if your first value there is a primary key, it would probably be better to assign it from a sequence.



回答2:

Solution 1) You can populate inside the loop a PL/SQL array and then just after the loop insert the whole array in one step using:

FORALL i in contracts_tab.first .. contracts_tab.last
  INSERT INTO w_contracts VALUES contracts_tab(i);

Solution 2) if the v_stmt contains a valid SQL statement you can directly insert data into the table using

EXECUTE IMMEDIATE 'INSERT INTO w_contracts (counter, cont_id, proj_nr) 
    SELECT rownum, 9, 3 FROM ('||v_stmt||')';


回答3:

"select statement is assembled from a website, ex if user choose to include more detailed search then the select statement is changed and the result looks different in the end. The whole application is a web site build on dinamic plsql code."

This is a dangerous proposition, because it opens your database to SQL injection. This is the scenario in which Bad People subvert your parameters to expand the data they can retrieve or to escalate privileges. At the very least you need to be using DBMS_ASSERT to validate user input. Find out more.

Of course, if you are allowing users to pass whole SQL strings (you haven't provided any information regarding the construction of W_STMT) then all bets are off. DBMS_ASSERT won't help you there.

Anyway, as you have failed to give the additional information we actually need, please let me spell it out for you:

  • will the SELECT statement always have the same column names from the same table name, or can the user change those two?
  • will you always be interested in the third and ninth columns?
  • how is the W_STMT string assembled? How much control do you have over its projection?