2013-04-14 235 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';