【发布时间】:2019-12-22 03:18:31
【问题描述】:
目前,我正在尝试实现一个数据读取器来执行一个特别大的查询。当前实现使用实体框架,但由于查询的性质,它非常慢(大约 4 分半钟)。
这是当前使用 EF 的实现:
public List<SomeDataModel> GetSomeData(List<string> SomeValues, string setId)
{
var ret = new List<SomeDataModel>();
using(var context = new SomeDBContext())
{
var data = context.SomeEntity.Where(x => x.SetId == setId && SomeValues.Contains(x.SomeValue));
data.ForEach(x => ret.Add(mapper.Map<SomeDataModel>(x))); // mapper is an instance of AutoMapper via dependency injection
}
return ret;
}
理想情况下,我想生成一个更基本的查询字符串并通过 OracleDataReader 提取数据。问题是这样的:在 Oracle 中的 IN 语句中,您只能有 1000 个值。 SomeValues 参数可以是 5,000 到 25,000 之间的任何值,所以我想在后端 EF 会自行生成多个查询,但就像我说的那样,它非常慢。
这是我试图采取的方向:
public List<SomeDataModel> GetSomeData(List<string> SomeValues, string setId)
{
var ret = new List<SomeDataModel>();
const int MAX_CHUNK_SIZE = 1000;
var totalPages = (int)Math.Ceiling((decimal)SomeValues.Count / MAX_CHUNK_SIZE);
for(var i = 0; i < totalPages; i++)
{
var chunkItems = SomeValues.Skip(i * MAX_CHUNK_SIZE).Take(MAX_CHUNK_SIZE).ToList();
pageList.Add(chunkItems);
}
using (var context = new CASTDbContext())
{
var connStr = context.Database.Connection.ConnectionString;
using (var conn = new OracleConnection(connStr))
{
foreach(var page in pageList)
{
var queryStr = string.Format("SELECT * FROM SomeTable WHERE SomeColumn IN ({0})", "(" + string.Join(",", page.ToArray()) + ")");
var cmd = new OracleCommand(queryStr, conn);
using (var reader = cmd.ExecuteReader())
{
while(reader.Read())
{
var newItem = new SomeDataModel();
newItem.Something = reader["Something"].ToString();
ret.Add(newItem);
}
}
}
}
}
return ret;
}
我认为期望的结果是为读者有效地生成多个查询,或者构建一个可以有效处理这种情况的查询。我在第二个示例中的内容是目前的占位符代码。
【问题讨论】:
-
你为什么使用
OracleDataReader?为什么不使用 EF 运行存储过程? -
不幸的是,不使用存储过程是一种肤浅的要求。它引用的表非常不稳定,并且引用它的其他存储过程存在问题,所以我被告知不要使用它。
-
如果您将要查询的项目列表拆分为页面,您是否尝试过使用 EF 执行此操作?这方面的表现如何?我的意思是像在第二个示例中那样构建
pageList,然后为每个页面执行Contains查询? -
很遗憾你不能使用 proc,否则你可以传递所有值 as an array 并且查询可能根本不需要时间。
-
@gnud 我也尝试过这条路线,但性能并没有太大差异。
标签: c# oracle entity-framework oracle11g odp.net