不幸的是,我还没有找到解决这个问题的好方法。到目前为止,我在这里看到的答案和问题都是关于有很多记录的大桌子。
我正在尝试使用以下代码查询名为Tickets的表:
var Status = ticketStatusService.GetByName("New");
string StatusID = Status.Id;
var tickets = db.Tickets.Where(e =>
!e.Deleted &&
e.Project == null &&
e.Status != null &&
e.Status.Id == StatusID);
var list = tickets.ToList();
该表当前有少于100条记录,此查询平均需要22秒才能执行。
代码优先模型如下:
public class Ticket : Base
{
[Key]
[Required]
public Guid Id { get; set; }
[Display(Name = "Date")]
public DateTime RowDate { get; set; } = DateTime.Now;
public bool Deleted { get; set; } = false;
[Index(IsUnique = true)]
public int? Number { get; set; }
[Display(Name = "Ticket Subject")]
public string Subject { get; set; }
[Display(Name = "Notes (Employees Only)")]
public string Notes { get; set; }
[Display(Name = "E-Mail")]
public string From { get; set; }
[Display(Name = "Phone Number")]
public string Phone { get; set; }
[Display(Name = "Secondary Phone Number")]
public string PhoneAlt { get; set; }
[Display(Name = "Client Name")]
public string Name { get; set; }
[Display(Name = "Message")]
public string Messages { get; set; }
[DataType(DataType.DateTime)]
public DateTime? OpenDate { get; set; }
[DataType(DataType.DateTime)]
public DateTime? CloseDate { get; set; }
[DataType(DataType.DateTime)]
public DateTime? AssignedDate { get; set; }
public bool? Origin { get; set; }
public virtual User AssignedUser { get; set; }
public virtual List<TicketFile> TicketFiles { get; set; }
public virtual List<Task> Tasks { get; set; }
public virtual Project Project { get; set; }
public virtual TicketStatus Status { get; set; }
public virtual TicketClosingCategory TicketClosingCategory { get; set; }
public virtual TicketGroup TicketGroup { get; set; }
public virtual TicketPriority TicketPriority { get; set; }
}
任何对此问题的见解将不胜感激。非常感谢你!
编辑:直接在SQL Server Management Studio上运行相同的查询也需要很长时间,大约需要9到11秒。因此表本身可能存在问题。
答案 0 :(得分:2)
我看到了一些可能的改进。
由于某些原因,您选择偏离entity framework code fist conventions。其中之一是使用List
而不是ICollection
,另一种是您省略提及外键。
使用ICollection代替列表
您确定Ticket.TicketFiles[4]
具有定义的含义吗? Ticket.TicketFiles.Insert(4, new TicketFile())
是什么意思?
最好坚持禁止使用没有定义含义的功能的接口。使用ICollection<TicketFile>
。这样,您将只有在数据库上下文中具有适当含义的函数。此外,它使实体框架可以自由选择最有效的集合类型来执行其查询。
让您的班级代表表格
让您的课程成为POCO。不要添加表中没有的任何功能。
在实体框架中,表的列由非虚拟属性表示。虚拟属性表示表之间的关系(一对多,多对多,...)
让实体框架决定最有效的方法来初始化序列中的数据。不要在创建列表的地方使用构造函数,列表会被实体框架立即丢弃,以其自身的ICollection
取代。如果实体框架立即用其自己的值替换属性Deleted
,请不要自动对其进行初始化。
您可能只有一个过程,将票证添加到数据库。使用此功能可以正确初始化任何“新添加的票证”的字段
别忘了外键
您在表之间定义了几个关系(一对多还是多对多?),但是却忘记了定义外键。由于使用了virtual
实体框架,因此可以理解它需要外键并将其添加,但是在查询中您需要编写e.Status != null && e.Status.Id == statusId
,而显然您只能使用外键{{1 }}。为此,您不必加入“状态”表
指定外键的另一个原因:它们是表中的实列。如果您定义这些类代表您的表,那么它们应该在这些类中!
仅选择您实际打算使用的属性
数据库查询的最慢部分之一是将所选数据从数据库管理系统传输到本地进程。因此,只选择您实际打算使用的数据是明智的。
示例。 e.StatusId == statusId
和User
之间似乎是一对多:每个用户拥有零个或多个Ticket
,每个Tickets
恰好属于一个{{1 }}。假设Ticket
4有20个User
。每个User
都会有一个值为{4的Tickets
。如果您在没有正确的Ticket
的情况下获取这20个UserId
,则将获取相同Tickets
的所有属性每个Select
传输4次,您将传输相同的User
的数据20次(包括他的所有属性以及他的所有关系)。多么浪费处理能力!
始终使用“选择”查询您的数据,并仅选择您实际打算使用的属性。仅在计划更新包含的数据时才使用包含。
Ticket