2012-09-28 64 views
2

我有这个疑问SQL数据库索引设计内加入关键字搜索

SELECT a.* 
FROM entries a 
INNER JOIN entries_keywords b ON a.id = b.entry_id 
INNER JOIN keywords c ON b.keyword_id = c.id 
WHERE c.key IN ('wake', 'up') 
GROUP BY a.id 
HAVING COUNT(*) = 2 

,但它的速度慢。我如何优化设计索引以加快速度?

编辑 这是当前模式

CREATE TABLE `entries` (`id` integer PRIMARY KEY AUTOINCREMENT, `sha` text); 
CREATE TABLE `entries_keywords` (`id` integer PRIMARY KEY AUTOINCREMENT, `entry_id` integer REFERENCES `entries`, `keyword_id` integer REFERENCES `keywords`); 
CREATE TABLE `keywords` (`id` integer PRIMARY KEY AUTOINCREMENT, `key` string); 
CREATE INDEX `entries_keywords_entry_id_index` ON `entries_keywords` (`entry_id`); 
CREATE INDEX `entries_keywords_entry_id_keyword_id_index` ON `entries_keywords` (`entry_id`, `keyword_id`); 
CREATE INDEX `entries_keywords_keyword_id_index` ON `entries_keywords` (`keyword_id`); 
CREATE INDEX `keywords_key_index` ON `keywords` (`key`); 

我使用SQLITE3,查询不会失败,但速度很慢。

现在我这样的查询(子查询为每个关键字):

select * 
from (
    select * 
    from (entries) e 
    inner join entries_keywords ek on e.id = ek.entry_id 
    inner join keywords k on ek.keyword_id = k.id 
    where k.key = 'wake') e 
inner join entries_keywords ek on e.id = ek.entry_id 
inner join keywords k on ek.keyword_id = k.id 
where k.key = 'up'; 

这是方式更快,但感觉不对,因为它会变得丑陋,如果我有很多的关键字。

+0

你现在有什么指标? – Taryn

+0

引用列上的索引将有所帮助。缓慢的部分可能是最后一点..计数*对于性能不是很好。我假设这是mysql,但如果它是另一个数据库,你可以使用keywords.key的部分索引作为优化。 –

+0

'keywords.key'编入索引吗? –

回答

1

该查询所需的关键指标

  • 关键字(关键字)
  • entries_keywords(keyword_id,entry_id)
  • 条目(ID)

您必须使用MySQL,因为否则SELECT a。*会失败。
编辑对本声明的第二个评论之后,让我指出为什么select a.*会在这里失败 - 这是因为GROUP BY的。

解释一下,因为条件(WHERE)在c.key上,所以需要对它进行索引。
然后,这会对b.keyword_id加入JOIN。我们创建一个包含b.entry_id的索引,以便它永远不必查询表格 - 索引本身可以覆盖所需的列。
最后,a.id = b.entry_id加入到条目表中,因此我们索引该表的id。

这很可能entries(id)已经是主键,但你可能有entries_keywords索引周围的其他的方式 - 它不会工作,以满足此连接。

+0

SELECT a。*在我所知道的任何RDBMS中都受支持...... – amphibient

+0

“失败”是一个相对术语,不幸的是。 MySQL允许您省略SQL标准和其他大部分DBMS要求的GROUP BY列表中的所有列 - 所有非聚合的列应正常列在GROUP BY子句中。 MySQL对此更为宽松,并选择要显示的值以适应自身。在分组列构成表的主键(或另一候选键)的超集的情况下,它可以得到你想要的答案;但是如果您正在分组的列不构成表的候选键的超集,则不确定性。 –

+0

@JonathanLeffler:确切地说,即使SQL-2003 +标准不在“GROUP BY”子句中,也允许在“SELECT”列表中使用列。只要他们在功能上依赖于他们。 (不是MySQL做任何检查,他们已经以一种相当马虎的方式实现了这一点 - 允许在查询中使用非标准的使用和半随机的结果。) –