Question

Some old code that I have uses OracleDataAdaper.Update(DataSet). If I call a test stored proc (that only has input parameters), it takes about 24 seconds for 20,000 rows to be inserted. I needed to improve on that, so I switched to using array binding. With array binding ExecuteNonQuery() takes under 3 seconds to insert the same 20,000 rows! That's a huge performance improvement and I also avoid creating expensive DataSets.

However, I got into problems with stored procs that have OUT parameter(s) or functions that return values.

Inserting same 20,000 rows via a stored proc that has an OUT parameter using OracleDataAdaper.Update(DataSet) takes about 26 seconds - which is 2 seconds or 8% slower than w/o OUT parameter - not bad.
But calling same stored proc using array binding causes ExecuteNonQuery() to run for 15 minutes! That's 300% slower than w/o OUT parameter!


For all OUT/IN OUT/RETURN parameters of variable-length type (i.e. VARCHAR2), I set OracleParameter.ArrayBindSize property to int[numOfRows] with all values set to max value for type (i.e. 4000 for VARCHAR2).

My test stored proc looks like this (in real life, I could be returning a sequence number):

    PROCEDURE INSERT_TEST(
        p_key            VARCHAR2,
        p_id             NUMBER,
        p_dt             DATE,
        p_unique_key OUT VARCHAR2)
      AS
      BEGIN
        INSERT INTO T_TEST_DAL(
                      UNIQUE_KEY,
                      NUM_ID,
                      DT_VAL)
        VALUES (
                 p_key,
                 p_id,
                 p_dt)
        RETURNING UNIQUE_KEY
          INTO p_unique_key;
    END INSERT_TEST;

I use ODP.NET Oracle.DataAccess v4.112.3.0, but I'm pretty sure it's not version-specific.

Has anyone faced similar issues with array-bound OUT parameters? Do I need to set another property for OUT/return parameters to speed this up?

What I'm hoping to accomplish is to improve performance without having to make changes on the database side. Perhaps using PLSQLAssociativeArray would speed things up (I haven't tried yet), but that would require too many changes to pre-existing stored procs.

Était-ce utile?

La solution

Turns out that ODP.NET does not provide a way to tune "fetch size" for ExecuteNonQuery() with array binding. So when a stored proc contains an OUT parameter (or function has RETURN parameter), Oracle sends results of each item back to caller separately. This results in a lot of networking overhead and significantly slows down the process.

When using OracleDataAdapter.Update(DataSet), the results of the execution are sent in batches, resulting in lower networking overhead.

When there are no OUT params, it's much faster to use ExecuteNonQuery() rather than OracleDataAdapter.Update(DataSet).

Autres conseils

Just to extend the answer with my experience. Using array binding for Inserts, Updates and Deletes performs wonderfully and ExecutNonQuery correctly returns the number of affected rows.

But because a Merge ExecuteNonQuery returns -1 for the number of affected rows you need to include the Rowcount as an Output parameter, which in turn slows everything down again.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top