2015-09-05 119 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