通过大量一对多映射提高查询性能
我正在使用 SQL Azure 实体框架,在我的应用程序的一页中,我们向用户显示了大量相关数据。我们在页面上最多加载 30 个项目,但每个项目都有 5 个到其他对象的一对多映射。查询时间处于合理的水平,但我在对象映射上泄漏了相当多的性能。 (几乎整整一秒)。
这是我的对象的示例
public class Task
{
public string Name {get; set;}
public string Status {get; set;}
public DateTime DueDate {get; set;}
public IEnumerable<TaskData> Data {get; set;}
public IEnumerable<Transaction> Transactions {get; set;}
public IEnumerable<File> Files {get; set;}
public IEnumerable<Comment> Comments {get; set;}
public IEnumerable<People> People {get; set;}
}
任务有名称、状态和截止日期。它还具有许多自定义名称/值对的任务数据、许多显示任务历史记录的事务、许多文件、许多评论和许多人员致力于此。
我的 EF 查询看起来像这样。
var Items = context.Items.Include(x=>x.Data).Include(x=>x.Files).Include(x=>x.Comments).Include(x=>x.People).Where(some constraint).ToList();
特定任务的相关性首先基于状态,然后基于截止日期。所以我创建了一个 IComparable 重写来与排序一起使用。关键是分页查询在这种情况下不能很好地工作,因为排序不是基于 int 或日期(我是对的吗?)
在我们应用程序的其余部分中,我们显示的有关每个任务的信息较少,并且Linq2Entities 工作得很好。不过,这种情况下的对象映射正在杀死我们。我已经走上了使用 Dapper 直接访问数据库的道路,但一对多映射有它的警告。对于一些关系,我认为这会很有效,但对于 5-6 个人来说就不行了。我接下来要看的是 PetaPoco,但我没走太远,我就想最好先在这里提出问题。
我试图带回这么多数据是疯了吗?为了获得最大性能,我有哪些选择?我会稍微复杂一些,因为它只是应用程序的一个区域。
I'm using Entity Framework to SQL Azure and in one page of my application we show quite a bit of related data to the user. We're loading a max of 30 items on the page but each item has 5 one-to-many mappings to other objects. The query time is at a reasonable level but I'm leaking quite a bit of performance on the object mapping. (almost a full second).
Here's an example of what my object looks like
public class Task
{
public string Name {get; set;}
public string Status {get; set;}
public DateTime DueDate {get; set;}
public IEnumerable<TaskData> Data {get; set;}
public IEnumerable<Transaction> Transactions {get; set;}
public IEnumerable<File> Files {get; set;}
public IEnumerable<Comment> Comments {get; set;}
public IEnumerable<People> People {get; set;}
}
A task has a name, a status and a due date. It also has many TaskData that are custom name/value pairs, many Transactions that show a history of the task, many Files, many Comments and many People working on it.
My EF query looks something like this.
var Items = context.Items.Include(x=>x.Data).Include(x=>x.Files).Include(x=>x.Comments).Include(x=>x.People).Where(some constraint).ToList();
The relevance of a specific task is based first on the status, and then on the due date. So I've created an IComparable override to use with sort. The point is that paged queries don't work well in this scenario because the sort isn't based off of an int or a date (am I right?)
In the rest of our application we're displaying less information about each task and Linq2Entities is working just fine. The object mapping in this case is killing us though. I've gone down the road of going straight to the DB with Dapper but one-to-many mapping has it's caveats. For a few relationships I think it would work well but not for 5-6. My next thing to look at was PetaPoco but I didn't get very far before I thought I'd better throw the question on here first.
Am I crazy for trying to bring back so much data? What are my options for getting maximum performance out of this? I'll take a little bit of complexity since its only one area of the application.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我敢打赌您的 EF 查询会拉回太多数据。问题是,“最佳”检索技术在很大程度上取决于所提取数据的类型和数量。
预先了解这一点可以让您根据预期的数据集调整运行的查询。
例如......如果您只提取有限数量的具有大量子实体的实体,我在这里编写的模式效果很好:
如何使用 Dapper 映射嵌套对象列表
如果您知道要拉取的 id 并且数量少于 2000 个,则可以通过以下方式快捷方式完成所有操作使用
QueryMultiple
查询单个网格和映射,例如:如果您要拉取更大的集合,您可能需要批处理或分阶段执行。
对于您的特定示例,我将查询
Tasks
以获取所有任务 ID 和数据,然后使用单个QueryMultiple
将关系映射到所有关联的表。I am willing to bet your EF query is pulling back too much data. The thing is, the "optimal" retrieval technique heavily depends on the type and amount of data being pulled.
Knowing that up front allows you to tune the queries you run based on your expected data set.
For example ... if you are only pulling a limited number of entities with lots of subentities the pattern I wrote here works well:
How do I map lists of nested objects with Dapper
If you know what ids you are pulling and there are less than 2000, you can shortcut it all by querying a single grid and mapping using
QueryMultiple
eg:If you are yanking a larger set you may need to batch, or do so in phases.
For your particular example I would query
Tasks
to get all the task ids and data, then map on the relations using a singleQueryMultiple
to all the associated tables.