在我的公司,我们有一个WPF应用程序,它可以连接到不同的数据库( MySQL,MySQL,SQLite和Oracle)。我们有许多表(有时是200+,不要问为什么,它非常复杂),我们的数据访问层有几个接口和虚拟/覆盖方法来处理特定数据库中的数据读取。这一点很重要,因为正如大多数教程所示,我们并不是专门在一个表上工作,而是动态创建了我们需要运行的特定于数据库的命令。在MS SQL、MySQL和SQLite下,一切都运行得很好,但在Oracle CLOB中读取速度非常慢。读取2000行数据需要40-50秒。不幸的是,在大多数情况下,我们不能假设我们不需要CLOB类型,因为我们正在以xml格式存储财务数据,有时它会超过4000,8000,甚至10k+字符长大小。我正在使用ODP.Net解决方案读取数据,这就是我正在做的事情:
我们的环境: Oracle: 11.2.0.1.0 VS: 2010,从我的Oracle主安装: C:\Oracle\ODP.NET\bin\4\Oracle.DataAccess.dll引用了专业版Oracle.DataAccess.dll
我的测试代码(来自我们的解决方案):
属性:
private string ConnectionString
{
get
{
return
string.Format(
"User Id={0}; Password={1}; POOLING=true;
Data Source= (DESCRIPTION=(ADDRESS=
(PROTOCOL=TCP)(HOST={2})(PORT={3})) (CONNECT_DATA=(SID={4})
(SERVICE_NAME={5})));",
"ourUser", "ourPassword", "ourHost", "ourPort", "ourSID",
"ourDatabaseName");
}
}
要运行的命令:
string sql = "SELECT * FROM OurTable";
//This table contains at least one CLOB column
和我们的测试代码:
List<object[]> readerList = new List<object[]>();
using (Oracle.DataAccess.Client.OracleConnection oraConn = new
Oracle.DataAccess.Client.OracleConnection(ConnectionString))
{
oraConn.Open();
Oracle.DataAccess.Client.OracleCommand oraComm = new
Oracle.DataAccess.Client.OracleCommand(sql);
oraComm.CommandType = CommandType.Text;
oraComm.Connection = oraConn;
Oracle.DataAccess.Client.OracleDataReader oraReader;
oraReader = oraComm.ExecuteReader();
oraComm.InitialLOBFetchSize = -1;
while (oraReader.Read())
{
object[] readObjects = new object[oraReader.FieldCount];
oraReader.GetValues(readObjects);
readerList.Add(readObjects);
}
oraConn.Close();
}
while迭代运行非常慢,除非我们不需要读取CLOB,因为在这种情况下它会很快。不幸的是,我不能制定特定于表的解决方案,因为不是在所有情况下,我都知道我必须处理哪些表(有时会动态创建表)。
那么,问题是:有没有什么解决方案可以让它像从MS SQL中读取文本类型对象一样快?
发布于 2013-12-12 22:07:33
查看命令对象中的属性FetchSize
,如下所示:Improve ODP.NET Performance
您可以像这样获得行的大小:
Public Function GetRowSize(ByVal cmd As OracleCommand) As Integer
Dim dr As OracleDataReader
dr = cmd.ExecuteReader()
Return CInt(dr.GetType.GetField("m_rowSize", Reflection.BindingFlags.Instance Or Reflection.BindingFlags.NonPublic).GetValue(dr))
End Function
在C#中,它看起来像这样:
public int GetRowSize(OracleCommand cmd)
{
OracleDataReader dr = cmd.ExecuteReader();
return (int)( dr.GetType().GetField("m_rowSize", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(dr) );
}
当您的应用程序启动时,您可以为每个不同的查询执行一次此函数,然后您可以重用该值。
我记得前段时间我也遇到过类似的问题。我的解决方案是选择没有任何CLOB列的表。为了获得CLOB值,我只对单个CLOB列和单个记录运行了一个额外的SELECT (使用像您一样的OracelDataReader )。
我还找到了这个文档:Obtaining LOB Data
https://stackoverflow.com/questions/20539886
复制相似问题