2013-10-27 57 views
2

我有这三个表嵌套查询:PostgreSQL的执行缓慢

  1. 创建表的话(ID整数,字文,频率整数);
  2. 创建表句(id整数,句子文本);
  3. 创建表索引(wordId integer,sentenceId integer,position integer);

索引是倒排索引,表示哪个词出现在哪个句子中。 Furthermoore我有一个来自表单词和句子的id的索引。

此查询确定哪些句子出现一个给定的字,并返回第一个匹配:

select S.sentence from sentences S, words W, index I 
where W.word = '#erhoehungen' and W.id = I.wordId and S.id = I.sentenceId 
limit 1; 

但是,当我想要检索其中两个词一起出现的一句话:

select S.sentence from sentences S, words W, index I 
where W.word = '#dreikampf' and I.wordId = W.id and S.id = I.sentenceId and 
S.id in (
    select S.id from sentences S, words W, index I 
    where W.word = 'bruederle' and W.id = I.wordId and S.id = I.sentenceId 
) 
limit 1; 

这查询要慢得多。有什么窍门可以加速吗?下面的事情我做了这么远:

  • shared_buffer将增加至32MB
  • 增加work_mem到15MB
  • 跑分析所有表上
  • 作为词ID和句子ID提到创建的索引

关心。

€秩:

这里是解释分析查询语句的输出:http://pastebin.com/t2M5w4na

这三个创建语句其实我原来的创建语句。我应该将主键添加到表格句子和单词中,并将它们作为索引中的外键引用?但是,我应该为索引表使用哪个主键? SentId和wordId在一起并不是唯一的,即使我添加表示单词在句子中的位置的pos也不是唯一的。

更新为:

  1. 创建表字(ID整数,字文本,频率整数,主键(id));
  2. 创建表句(id整数,句子文本,主键(id)); (wordId integer,sentenceId integer,位置整数,外键(wordId)引用单词(id),外键(sentenceId)引用句子(sentenceId));创建表索引
+1

编辑你的问题,并粘贴的输出'解释分析your_query',其中 “your_query” 代表你的麻烦SELECT语句。而且,实际的CREATE TABLE语句可以帮助很多。 –

+0

你的表'索引'(可怕的名字,BTW)至少需要一个主键。 “{sentenceid,position}”是明显的选择。在'{sentenceid,wordid}'和/或'{wordid,sentenceid}'上有一个或两个复合索引也可能有帮助。 – wildplasser

+0

加号:对于单词表的_natural_键,您需要一个UNIQUE约束或索引:“单词”本身。不记录:RDBMS和nlp是不匹配的。您可以查看其他存储方法(对于Postgres:hstore或GIST索引进行全文搜索) – wildplasser

回答

1

我想这应该是更有效:

SELECT s.id, s.sentence FROM words w 
JOIN INDEX i ON w.id = i.wordId 
JOIN sentences s ON i.sentenceId = s.id 
WHERE w.word IN ('#dreikampf', 'bruederle') 
GROUP BY s.id, s.sentence 
HAVING COUNT(*) >= 2 

只需确保IN子句中的项目数量的HAVING子句中的项目数量相匹配。

小提琴here

+0

如果你想添加更多的单词,而是改变参数,你也不需要在这个解决方案中添加更多的SQL代码:) –

+0

非常感谢。它比我的解决方案快得多,但仍然在几秒钟内。也许这是因为表格的大小:单词(255715行),句子(5085623行)和索引(61029790行)。 – user2715478

+0

61 MM?这是一个很大的数字:)下一级的性能将在我猜测的索引上工作。但可能你应该在[dba.se]中提出这个问题。 –

0

看起来您没有索引wordId,sentenceId。请创建它们,并且查询将运行得更快。

CREATE INDEX idx_index_wordId ON index USING btree (wordId); 
CREATE INDEX idx_index_sentenceId ON index USING btree (sentenceId); 

使用保留字作为index表名是不是一个好主意 - 你可能需要逃避它在某些情况下。 也许你还应该添加id列到index表,并使其成为主键。

请在使用索引后使用Mosty Mostacho查询并显示它的输出为explain analyze。可能会更快。

更新:

请尝试新的查询:

select S.sentence from sentences S where S.id in 
(select sentenceId from index I where 
I.wordId in (select id from words where word IN ('#dreikampf', 'bruederle')) 
group by I.sentenceId 
having count(distinct I.wordId) = 2 
limit 1) 
+0

向两个id添加了索引,并将索引表重命名为inv_w。以下是解释分析的输出:pastebin.com/veVds6KP仍以秒为单位。我只对第一个/一个匹配感兴趣,所以也许我可以使用游标?因为此查询检索所有解决方案。 – user2715478

+0

请同时创建此索引: CREATE INDEX idx_words_word使用btree(字)开启单词;' 并在查询结尾添加'LIMIT 1'以仅提取一行。 – alexius

+0

我也更新了我的答案 - 请尝试新的查询。它应该更快,更正确地工作(当两个相同的单词在一个句子中时处理案例)。 – alexius