2013-10-27 3 views
2

У меня есть эти три таблицы:PostGreSQL Вложенный запрос исполняющей медленно

  1. создать таблицу слов (ID целочисленные, текст слово, частота целое число);
  2. создание табличных предложений (целое число, текст предложения);
  3. создать индекс таблицы (wordId целое число, предложениеId целое число, целое целое);

Индекс - инвертированный индекс и обозначает, какое слово встречается в этом предложении. Дальше я имею индекс на 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 до 15Мб
  • бегала анализа всех таблиц
  • как уже упоминалось, созданный индекс на слова ид и приговаривает ид

С уважением.

€ Дит:

Вот выход объяснения анализа оператора запроса: http://pastebin.com/t2M5w4na

Эти три создания заявления на самом деле мои оригинальные создания заявления. Должен ли я добавлять первичный ключ к таблицам предложений и слов и ссылаться на них как на внешние ключи в индексе? Но какой первичный ключ я должен использовать для таблицы индексов? SentId и wordId вместе не являются уникальными, и даже если я добавляю pos, который обозначает положение слова в предложении, он не является уникальным.

обновлена:

  1. создать табличные слова (идентификатор целочисленные, текст слово, частота целочисленные, первичный ключ (идентификатор));
  2. создание табличных предложений (целое число, текст предложения, первичный ключ (id));
  3. create table index (wordId integer, предложениеId целое число, целое число, внешний ключ (wordId) ссылки слова (id), внешний ключ (предложениеId) ссылки предложения (предложениеId));
+1

Редактировать ваш вопрос, и вставить вывод 'объяснить анализ your_query', где "your_query" представляет свой хлопотно ЗЕЬЕСТ. Кроме того, реальные инструкции CREATE TABLE могут помочь. –

+0

Ваш индекс 'index' (ужасное имя, BTW) должен иметь по крайней мере первичный ключ. '{sentenceid, position}' является очевидным выбором. Возможно, тоже поможет один или два составных индекса на '{sentenceid, wordid} и/или' {wordid, sentenceid}. – wildplasser

+0

Плюс: вам понадобится UNIQUE ограничение или индекс для ключа _natural_ таблицы слов: самого слова. off-record: 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.

Fiddle 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 выход после внесения индексов. Может быть, он может работать еще быстрее.

Update:

пожалуйста, попробуйте новый запрос:

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

добавлен индекс для обоих идентификаторов и переименован в индексную таблицу в inv_w. Вот результат анализа объяснения: pastebin.com/veVds6KP Еще в секундах. Меня интересует только первое/одно совпадение, так что, возможно, я могу использовать курсор? Потому что этот запрос извлекает все решения. – user2715478

+0

Также создайте этот индекс: 'CREATE INDEX idx_words_word ON words ИСПОЛЬЗОВАНИЕ btree (word);' и добавьте 'LIMIT 1' в конец запроса для извлечения только одной строки. – alexius

+0

Я также обновил свой ответ - попробуйте новый запрос. Он должен работать быстрее и правильнее (обрабатывать случаи, когда в одном предложении есть два одинаковых слова). – alexius

Смежные вопросы