问题
I'm having a lot of trouble with the OracleDataReader in ODP.Net. Basically, I have a parameterized query that takes anywhere from 1-5 seconds to run (returning around 450 records) and then takes 60-90 seconds to loop over (with no code even running in the loop, literally iterating over the recordset and doing nothing).
When I run it from Aqua Data Studio it takes 1-5 seconds. When I run it from .Net it takes 1-5 seconds for cmd.ExecuteReader() to return. When I loop over the 450 records with OracleDataReader.Read it takes 60-90 seconds to finish.
I even took out all of the code in the loop and just had a blank "While dr.Read" and it still took 60 to 90 seconds to loop over those 450 records (I used a Stopwatch to get the time for the cmd.ExecuteReader and then around the empty dr.Read loop).
I have tried setting the FetchSize, it didn't help (and, it's only 450 records in my test case). I have tried turning auto tuning off with the connection string, it degraded performance even more.
Why is the OracleDataReader.Read taking so long when it's a small amount of data being returned (and other tools return the same data for the same query in a fraction of the time)?
Using conn As New Oracle.DataAccess.Client.OracleConnection(System.Configuration.ConfigurationManager.ConnectionStrings("oracle_dss").ConnectionString)
conn.Open()
Using cmd As OracleCommand = conn.CreateCommand
cmd.BindByName = True
cmd.CommandText = "" ' removed SQL to make this more readable
' Month end
Dim paramMonthEndDate As OracleParameter = cmd.CreateParameter
paramMonthEndDate.ParameterName = ":month_end_date"
paramMonthEndDate.DbType = DbType.Date
paramMonthEndDate.Value = monthEnd
cmd.Parameters.Add(paramMonthEndDate)
Dim sw As New System.Diagnostics.Stopwatch
sw.Start()
cmd.FetchSize = 1000
Dim dr As OracleDataReader = cmd.ExecuteReader
dr.FetchSize = dr.RowSize * 1000
sw.Stop()
Me.Log(String.Format("Month End Query: {0}s", sw.ElapsedMilliseconds / 1000))
sw.Reset()
sw.Start()
While dr.Read
End While
sw.Stop()
Me.Log(String.Format("Month End Query through recordset: {0}s", sw.ElapsedMilliseconds / 1000))
dr.Close()
End Using
conn.Close()
End Using
回答1:
Work with your DBAs and ask them to capture an explain plan for both the stand alone run (aqua data studio) and your odp.net call and confirm they are in fact the same. If they are not, then that will probably explain your problem. You can then try adding "enlist=false" to your connection string but better yet have the DBA's update the statistics on the related tables, hopefully fixing the slow plan. See https://stackoverflow.com/a/14712992/852208 for more info.
I have had this same issue and it came down to oracle being less optimistic about the execution plan when a distributed transaction could be involved.
回答2:
May be I am wrong, but you actually fetch the data in this row: While dr.Read
, and not when you are executing the reader. So this can explain why even without doing nothing, dr.Read
take all your time.
I'd try to change your command to
1). Run plain sql (without parameters)
2). Run using regular (not binding variable) parameter
3). Move the sql code to Stored Procedure if possible
来源:https://stackoverflow.com/questions/15884433/odp-net-oracledatareader-read-very-slow