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)

我的主要任务是查询这个数据库。假设我搜索“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

重建我的对象。这对我来说看起来很麻烦,而且很慢。我看不出如何通过使用连接或其他方式显着改善这一点。我很难将这些对象建模为数据库中的关系。这是一个合适的设计吗?

我怎样才能更有效地提高查询时间?

4

1 回答 1

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';
于 2013-04-15T04:44:01.853 回答