在我的公司,我们有一个WPF应用程序,它可以连接到不同的数据库(MS SQL,MySQL,SQLite和Oracle)。我们有很多表(有时200多个,不要问为什么,它非常复杂),我们的dataaccess层有几个接口和虚拟/重写方法来处理特定数据库中的数据读取。重要的是,因为我们没有像大多数教程所示那样专门在一个表上工作,而是我们动态创建了我们需要运行的特定于数据库的命令。在MS SQL,MySQL和SQLite下一切运行良好,但在Oracle CLOB中读取速度非常慢。要读取2000行数据,需要40-50秒。不幸的是,在大多数情况下,我们不能假设我们不需要CLOB类型,因为我们以xml格式存储财务数据,有时它超过4000,8000甚至10k + char-long大小。我正在使用ODP.Net解决方案来读取数据,这就是我正在做的事情:
我们的环境: Oracle:11.2.0.1.0 VS:2010年,专业版 我的Oracle主页安装引用了Oracle.DataAccess.dll: C:\甲骨文\ ODP.NET \ BIN \ 4 \ 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中读取TEXT类型对象一样快?
答案 0 :(得分:2)
我知道这是旧的,但我遇到了类似的问题。在 OracleCommand 上设置 InitialLOBFetchSize = -1对我来说有很大的不同。我的CLOB列具有一致且合理的大小,因此这个设置对我来说很有意义。
通过将 InitialLOBFetchSize 设置为-1,可以从数据库中获取选择查询的整个LOB数据,而无需选择列表中的主键,ROWID或唯一列。当InitialLOBFetchSize设置为-1时,将在OracleDataReader对象上的Read方法调用期间获取并缓存整个LOB列数据。
更多详情在这里: https://docs.oracle.com/cd/B28359_01/win.111/b28375/featData.htm#BABFGDGJ
答案 1 :(得分:0)
很难确切说明导致缓慢的原因。但我很确定clob不应该像这样正常减速。
最好缩小C#代码(odp.net访问方式)或oracle服务器是否是根本原因。在甲骨文方面有各种方法可以识别。我要尝试的第一件事是使用SET AUTOTRACE ON在sql * plus上执行SQL,这将告诉我们在oracle服务器上的行为。
答案 2 :(得分:0)
查看Command对象中的属性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