我有一个复杂的字典数据库方案。每个对象(本质上是一个翻译)与此类似:
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)
我的主要任务是查询此数据库。假设我搜索“foo”,我目前的处理方式是:
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 :(得分:1)
在循环中调用的每个查询都至少需要执行一定的基本持续时间,即使对于简单的查询也是如此。许多环境因素影响了这个持续时间,但现在我们假设它是10毫秒。如果第一个查询匹配100个条目,则至少有301个查询被调用,每个查询占用10毫秒,总共3秒。循环迭代次数的变化会导致性能的显着变化。
使用连接重构查询将创建更复杂的查询,但调用的查询总数可以减少到固定数量,在下面的查询中为4。现在假设每个查询执行时需要50毫秒,因为它更复杂,总持续时间变为200毫秒,从3000毫秒大幅减少。
下面显示的4个查询应该接近达到预期的结果。还有其他方法可以编写查询,例如使用子查询或在FROM子句中包含表,但这些方法显示了如何使用JOIN进行查询。条件entries.keyword = 'foo'
用于表示原始查询中的条件以选择条目。
值得注意的是,如果foo
上的entries
条件计算成本非常高,则可能需要进行其他优化以进一步提高性能。在这些示例中,条件是一个简单的比较,可以在索引中快速查找,但使用可能需要全表扫描的LIKE
可能无法很好地处理这些查询。
以下查询选择与原始查询匹配的所有示例。原始查询中的条件在WHERE
列上表示为entries.keyword
子句。
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';