【发布时间】:2015-09-02 14:01:45
【问题描述】:
我编写了一个 asp.net 网站,用于创建包含指定项目的报告(到 Excel 中)。我通过 EF 从 SQL DB 获取这些项目。查询效果很好,大约需要 2000 个项目,大约需要 1 毫秒。
var itemsToQuery = (from i in context.item
where ......
.....
.....
orderby .......
select new
{
fields.....
});
现在对我来说变得很棘手。对于每个项目,我必须从数据库中查询额外的数据(第一次查询没有机会获得这些数据)。我只使用一个数据库连接到安全时间(用于主查询和方法中的所有其他查询)。我认为我的性能问题从这里开始。我有 2000 个项目,以下循环如下所示:
foreach(var item in itemsToQuery)
{
another query;
another query;
another query;
etc.....
// at the end it looks like
datatable.add(item.name, item.number, item.stuff ......);
}
所以我正在为这 2000 个项目中的每一个做另外 8 个查询。这个 foreach 大约需要 5 分钟才能完成(取决于项目的数量)。之后我需要这个 DataTable 来填充我的 Excel 表。这很好用而且“很快”。
您能否给我一些专家建议,如何使这个循环、查询或 DataTable 的填充更高效?
我想到了一个多任务处理的解决方法,并创建了一个站点,您可以在其中查看 excel 的状态(通过 ajax 调用),完成后您可以下载它。现在我只是阻止了这个网站的用户界面,用户必须坐在屏幕前,直到它完成而没有任何信息他需要等待多长时间。运行时钟的带有 gif 和 js 的屏幕示例:
一件重要的事情 - 我不能在数据库中创建视图或存储过程,因为我不允许这样做。我必须在后面的代码中执行每个查询等。
我知道这个程序是业余编写的,但这就是为什么我必须紧急改变它。
[编辑]
这是我讨论过的示例查询!仅供参考 - 我没有写每个查询。其中一些(如owner 或monthlyWorkTime)来自外部资源。
String changeDate = CalcÄnderungsDat(context
.ticket_history
.FirstOrDefault(x => x.history_type_id == 25 && x.ticket_id == item.ticketID).change_time.ToString());
String finishdate = CalcFinishDat((from tih in context.ticket_history
where (tih.name == "Reset of unlock time." && tih.ticket_id == item.ticketID)
|| (tih.state_id == 2 && tih.history_type_id == 1 && tih.ticket_id == item.ticketID)
select tih.change_time).Max().ToString());
try
{
string owner= (from a in context.article
where
item.ticketID == a.ticket_id &&
a.id ==
(from art in context.article
where art.a_subject.Contains("esitzer")
&& art.ticket.id == item.ticketID
&& art.ticket_id == art.ticket.id
select new { art.id }).Max(p => p.id)
select new { a.a_from }).FirstOrDefault().a_from;
}
catch (Exception)
{
string owner = (from a in context.article
where a.ticket.id == item.ticketID && a.ticket_id == a.ticket.id &&
a.id ==
(from art in context.article
where art.ticket.id == item.ticketID
&& art.ticket_id == art.ticket.id
select new { art.id }).Min(p => p.id)
select new { a.a_from }).FirstOrDefault().a_from;
}
decimal? monatszeit = (from ta in context.time_accounting
where
ta.change_time >= startdat &&
ta.change_time <= enddat &&
ta.ticket_id == item.ticketID
group new { ta } by new
{
ta.ticket_id,
ta.ticket.id,
ta.ticket.tn
} into g
select new
{
Zeiteinheit = (Decimal?)g.Sum(p => p.ta.time_unit),
}).SingleOrDefault().Zeiteinheit;
等等。总体而言,主查询中的每个项目有 7 个查询和 1 个外部方法用于计算特殊日期(此方法不应该是问题)。我怎样才能把它们放在一个完整的查询中?它会提高我的表现吗?
[编辑 - 再试一次!]
你对这个流程图有什么看法?
- 客户端向服务器发送请求服务器写入一个条目到 数据库中的“工作”表
- 发送请求后,客户端从数据库中获取job_ID 立即
- 使用此 ID 的客户端可以对进度(状态)进行 AJAX 调用
- Web 服务每秒检查一次是否有新作业 数据库中的状态 -1
- 为每个状态为 -1 的作业创建一个新任务
- 在此任务中,ReportMaker.GenerateReport(idAUFTRAG) 方法将是 叫
- ReportMaker 有一个事件 ReportProgress
- 调用者(任务)订阅此事件并将每个更改写入 数据库
- 数据库访问器 -> 任务
- 客户端执行 Ajax 回调
那肯定会提高性能!!!对于这样一个小项目来说,听起来是不是工作量太大了?
【问题讨论】:
-
还有什么疑问?为什么您必须为每个项目执行它们而不是创建关系并在单个查询中加载所有内容,例如使用
Include子句? -
鉴于
every following query得到single data from non relational tables,这不意味着确实存在关系吗? -
是的,这就是我的意思,它们是相关的,只是没有写入数据库约束。如果它们可以通过一个公共字段相关联,那么应该很有可能在一个查询中获得您想要的所有内容。但这里有另一种方法:你说你不能创建视图或过程,但是索引呢?查看“主要”查询和“依赖”查询的执行计划,寻找诸如
Index Scan之类的浪费部分,并尝试用Index Seeks正确使用索引来替换它们,这样可以加快速度无需更改代码即可。 -
如果您太受限制,您总是可以将处理拆分为单独的 ajax 请求,这样用户就可以不断获得更新并且感觉响应迅速。恐怕您的受限问题没有神奇的解决方案。最好的方法是 DrCopyPaste 解释的方法,但如果这不是一种选择......
-
我强烈建议您在 try/catch 块中修复该查询。最有可能的是,您捕获的异常是来自
.FirstOrDefault().a_from的NullReferenceException。如果FirstOrDefault()返回null,则抛出异常。将 try/catch 替换为if语句检查null。
标签: c# asp.net sql-server excel datatable