2013-04-14 279 views
2

我有一個字典的複雜數據庫方案。每個對象(本質上是一個翻譯)與此類似:如何建模和查詢關係數據庫中的對象?

Entry { 
    keyword; 
    examples; 
    tags; 
    Translations; 
} 

Translation { 
    text; 
    tags; 
    examples; 
} 

Example { 
    text; 
    translation; 
    phonetic_script; 
} 

即標籤(即語法),可以屬於關鍵字本身,或翻譯(外語的語法)和類似的例子可以屬於翻譯本身(即解釋外來詞)或者條目中的文本。我結束了此類關係設計的:

entries(id,keyword,) 
tags(tag) 
examples(id,text,...) 
entrytags(entry_id,tag) 
entryexamples(entry_id,example_id) 
translations(id,belongs_to_entry,...) 
translationtags(transl_id, tag) 
translationexamples(transl_id,example_id) 

我的主要任務就是查詢這個數據庫。說我搜索「富」,我目前的處理方式是:

query all entries with foo, get ids A 
foreach id in A 
    query all examples belonging to id 
    query all tags belonging to id 
    query all translations belonging to A, store their ids in B 
    foreach tr_id in B 
     query all tags belonging to tr_id 
     query all examples belonging to tr_id 

重建我的對象。這看起來很麻煩,而且很慢。我不明白我可以通過使用連接或其他方式顯着改善這一點。我很難將這些對象建模爲數據庫中的關係。這是一個適當的設計?

我該如何提高查詢時間的效率?

+0

我可能會考慮一個不同的數據庫解決方案,如NoSQL。 RDBMS不是一切的解決方案。 – Amirshk

回答

1

在循環中調用的每個查詢都至少需要一定的基本持續時間才能執行,即使對於普通查詢也是如此。許多環境因素會影響這個持續時間,但現在讓我們假設它是10毫秒。如果第一個查詢匹配100個條目,則至少有301個查詢被調用,每個查詢需要10 ms,總共需要3秒。循環迭代的次數各不相同,這可能會導致性能的顯着變化。

使用連接重構查詢將創建更復雜的查詢,但被調用的查詢總數可以減少到下面查詢中的固定數字4。現在假設每個查詢現在執行需要50毫秒,它比較複雜,總持續時間變爲200毫秒,從3000毫秒大幅減少。

下面顯示的4個查詢應該接近達到所需的結果。還有其他方法來編寫查詢,例如使用子查詢或在FROM子句中包括這些表,但這些方法顯示如何使用JOIN執行查詢。條件entries.keyword = 'foo'用於表示原始查詢中用於選擇條目的條件。

值得注意的是,如果entries上的foo條件計算起來非常昂貴,那麼可能需要其他優化來進一步提高性能。在這些示例中,條件是在索引中快速查找的簡單比較,但使用可能需要全表掃描的LIKE可能無法很好地處理這些查詢。

以下查詢選擇與原始查詢匹配的所有示例。原始查詢的條件表示爲entries.keyword列中的WHERE子句。

SELECT entries.id, examples.text 
    FROM entries 
INNER JOIN entryexamples 
    ON (entries.id = entryexamples.entry_id) 
INNER JOIN examples 
    ON (entryexamples.example_id = examples.id) 
WHERE entries.keyword = 'foo'; 

此查詢選擇與原始查詢匹配的標籤。在這種情況下僅使用兩個連接,因爲entrytags.tag列是需要的,加入tags只會提供相同的值。

SELECT entries.id, entrytags.tag 
    FROM entries 
INNER JOIN entrytags 
    ON (entries.id = entrytags.entry_id) 
WHERE entries.keyword = 'foo''; 

該查詢選擇原始查詢的翻譯標籤。這與前面的查詢類似,選擇entrytags,但此處使用另一層連接進行翻譯。

SELECT entries.id, translationtags.tag 
    FROM entries 
INNER JOIN translations 
    ON (entries.id = translations.belongs_to_entry) 
INNER JOIN translationtags 
    ON (translations.id = translationtags.transl_id) 
WHERE entries.keyword = 'foo'; 

最後的查詢做同樣作爲examples第一查詢,但也包括了額外的連接。它需要大量的連接,但通常應該比循環和執行單個查詢要好得多。

SELECT entries.id, examples.text 
    FROM entries 
INNER JOIN translations 
    ON (entries.id = translations.belongs_to_entry) 
INNER JOIN translationexamples 
    ON (translations.id = translationexamples.transl_id) 
INNER JOIN examples 
    ON (translationexamples.example_id = examples.id) 
WHERE entries.keyword = 'foo';