2015-09-05 80 views
0

我想用一个例子来解释我的问题。假设有很多课程可供学生注册。每门课程可以有很多讨论墙。每个讨论墙都包含问题。每个问题可能有答复。并且可以将徽章分配给答复(或评论)。数据库冗余与代码效率

在我的情况下,我需要知道哪个回复属于哪个课程(列出回复时),以及相同的徽章。我可以用Entity Framework做到这一点,但查询变得非常复杂并且导致性能问题。

在这种情况下,在回复(或BadgeAssignments)表中有一个CourseId列更好吗?或不?这会使我的生活在某些方面变得更加轻松,但从长远来看不确定。你怎么看?有些冗余有时会更好吗?我不认为我需要稍后更新CourseId字段。

+2

这是我的信念,在这两个之间的最佳平衡可能能但如果没有关于规模,用途或结构的更多具体信息,则难以评估,还是这种假设?在这种情况下不应该是程序员? –

+0

这是我正在开发的应用程序。你能详细说明你的意思的大小,结构等吗? @ J-Boss – renakre

+0

好吧,例如,你在Entity Framework中这样做,你期望或者有多少学生记录,你总共有多少课程等等。对于使用多少访问,通过什么意味着,您可能会得到多少这些高度复杂的联结?可以通过重新规范化对象框架来解决吗?按结构我的意思是多少个实体,有多少个类型?例如: –

回答

0

我会张贴在这里一个例子:

public class SchoolEntities : DbContext 
{ 
    public DbSet<Department> Departments { get; set; } 
} 

public class Department 
{ 
    // Primary key 
    public int DepartmentID { get; set; } 
    public string Name { get; set; } 

    // Navigation property 
    public virtual ICollection<Course> Courses { get; set; } 
} 

public class Course 
{ 
    // Primary key 
    public int CourseID { get; set; } 

    public string Title { get; set; } 
    public int Credits { get; set; } 

    // Foreign key 
    public int DepartmentID { get; set; } 

    // Navigation properties 
    public virtual Department Department { get; set; } 
} 

public partial class OnlineCourse : Course 
{ 
    public string URL { get; set; } 
} 

public partial class OnsiteCourse : Course 
{ 
    public string Location { get; set; } 
    public string Days { get; set; } 
    public System.DateTime Time { get; set; } 
} 

,这是一个小例子确实有任何信息?

+0

感谢的例子,是的,我总共有大约50实体,不知道哪个共享。我只是想学习这方面的最佳做法。 – renakre

2

我的宠物狗牺牲了性能方面的数据完整性。更快地获得不太可靠的答案不是一个好的解决方案。但是,改善性能并不会牺牲数据完整性的更改很好。

冗余可能会牺牲数据完整性。肯定是异常数据可以开始的关键点。问题是两套数据必须严格同步,这取决于设计,可能很容易或难以完成。无论哪种方式,都需要系统资源来保持同步,因此您将在性能上再添一笔。

幸运的是,该性能命中将被添加到DML操作中,因为这是执行同步的地方。通常,将查询转换为DML的性能时间(通常对响应时间不太敏感)可能是一个很好的解决方案。

然而,魔鬼是在细节中,你没有提供任何细节。性能可以在没有冗余的情况下得到充分改进冗余数据之间保持同步的困难程度如何?问最后一个问题的另一种方式是:异常(非同步)数据有多大可能进入系统?未解决的数据会有多大的问题,解决这个问题有多困难?

没有足够的信息来回答这些问题。但是当你调查解决方案时,记住它们。

2

系统的每个组件都应该被使用,因为它被设计成使它成为“最好的”。当他们根据他们的设计工作时,事情会变得更好。严格来说,这是我对你的问题的回答。

关系数据库

关系数据库的目的首先是执政的你的信息的完整性和第二提供了存储和检索系统。 RDMS管理你的真相,然后决定它应该被存储和检索的方式。

由于我们难以但不是不可能想象数字讨论墙的独特性以及问题和答案,因此我们将典型地使用用于这些实体的主键的代用键(即自动生成的数字)。这意味着将课程ID添加到问题,回复或BadgeAssignments的决定将违反校长关系设计。在这种情况下,你可能会说“没有什么大不了”,但它仍然是一种违法行为,只要它持续下去(双关语意),就会产生后果。

如果我们对课程,墙,问题,答复和BadgeAssignments使用了自然键,那么这些表中的每个表的主键都是来自这些表的组合。例如,我们会在复合答案的主键中包含课程的主键,而不会违反任何冗余或正常化的原则,并且您的生活将“更容易”。

这就是说,这个查询有什么难的?

SELECT 
    D.CourseId, D.CourseName 
    ,A.ReplyId, A.ReplyName 
FROM 
    Replies A 
    JOIN Questions B On A.QuestionId = B.QuestionId 
    JOIN Walls C ON B.WallId = C.WallId 
    JOIN Courses D ON C.CourseId = D.CourseId 

实体框架

实体框架(EF)可以配置无论我们把CourseId在回复还是依靠我们加入,以符合您的设计。但是,当谈到SQL性能时,我们通常可以比EF做得更好。

一个选项将是根据您的需要制作一个SQL查询(从上面的一个开始),它具有最高的优化量,并将其转换为View。然后,将C#类映射到View(而不是表),并简化了交互。我们会让EF超出提供低麻烦数据访问和SQL成功检索数据。

下面是对

var replies = context.RepliesView.Where(x => x.CourseId == 1).ToList(); 
+0

感谢您的回答!我有个问题。如果我想检索问题列表和每个问题的CourseId,那么我如何使用'ReplyView'?我是否需要使用第一个'context.RepliesView.Where',然后将结果映射到新的课程对象? – renakre

+0

抱歉耽搁...你可能需要一个新的类,称之为'QuestionView',将使用中的联接回到课程实体。当你想检索'QuestionsView'对象(S),则你可以使用像'context.QuestionView.Where'来查询'DbSet'。 –

1

既然您已为问题与在C#中的LINQ的区别...

var replies = context.Replies 
    .Where(x => x.Questions.Walls.CourseId == 1) 
    .Select(x => new ReplyView 
    { 
     CourseId = x.Questions.Walls.Courses.CourseId, 
     CourseName = x.Questions.Walls.Courses.CourseName, 
     ReplyId = x.ReplyId, 
     ReplyName = x.ReplyName 
    }).ToList(); 

,我假设你正在使用SQL Server,其中你可能会考虑使用indexed views来“缓存”JOIN,而不必担心这个缓存会不同步--DBMS会随时为你维护它。

例如,您可以缓存课程,学生,讨论墙,问题,回复和徽章之间的JOIN。因此,当您想知道哪个徽章属于哪个课程时,您只需从索引视图中检索一行,而不是执行物理JOIN。


另外,考虑重新设计你的钥匙,并使用identifying relationships关键领域迁移下来的外键的层次结构,所以查询子表,你可以得到一个非直接父的关键之间没有连接表”时, ”。


最后但并非最不重要的,我热烈推荐阅读Use the Index, Luke!对基本知识的每个开发人员应该对数据库性能......

+0

感谢您的回答,您是否暗示当您提到缓存时的意见? – renakre

+0

@erkaner我暗示索引视图。 “观点”和“索引视图”有些相关但并不相同。 –

+0

我会检查这些,谢谢你的宝贵信息。现在,我不知道谁应该获得赏金:(他们都是伟大的答案.. – renakre