Почему Solr намного быстрее, чем Postgres?

недавно я переключился с Postgres на Solr и увидел, что ~50x ускоряется в наших запросах. Запросы, которые мы запускаем, включают несколько диапазонов, и наши данные-это списки транспортных средств. Например: "найти все автомобили с пробегом

Я создал индексы для всех соответствующих столбцов в Postgres, поэтому это должно быть довольно справедливое сравнение. Глядя на план запроса в Postgres, хотя он все еще использовал один индекс, а затем сканировал (я предполагаю потому что он не мог использовать все разные индексы).

Как я понимаю, Postgres и Solr используют смутно похожие структуры данных (B-деревья), и они оба кэшируют данные в памяти. Поэтому мне интересно, откуда такая большая разница в производительности.

какие различия в архитектуре объясняют это?

5 ответов


во-первых, Solr не использует B-деревья. Индекс Lucene (базовая библиотека, используемая Solr) состоит из только для чтения сегментов. Для каждого сегмента Lucene поддерживает словарь терминов, который состоит из списка терминов, которые появляются в сегменте, лексикографически отсортированных. Поиск термина в этом словаре терминов производится с использованием двоичного поиска, поэтому стоимость однократного поиска O(log(t)) где t-количество терминов. Напротив, используя индекс стандартной РСУБД затраты O(log(d)) где D-количество документов. Когда многие документы имеют одинаковое значение для некоторого поля, это может быть большой выигрыш.

кроме того, Lucene committer Уве Шиндлер добавил поддержку очень performant запросы числового диапазона несколько лет назад. Для каждого значения числовое поле, в Lucene хранит несколько значений с разной точностью. Это позволяет Lucene выполнять запросы диапазона очень эффективно. Поскольку ваш use-case, похоже, использует числовой диапазон запросы много, это может объяснить, почему Solr намного быстрее. (Для получения дополнительной информации прочитайте javadocs, которые очень интересны и дают ссылки на соответствующие исследовательские работы.)

но Solr может сделать это только потому, что у него нет всех ограничений, которые есть у СУБД. Например, Solr очень плохо обновляет один документ за раз (он предпочитает пакетные обновления).


вы не очень много говорили о том, что вы сделали, чтобы настроить экземпляр PostgreSQL или ваши запросы. Нет ничего необычного в том, что 50X ускоряет запрос PostgreSQL путем настройки и/или повторной настройки запроса в формате, который оптимизируется лучше.

возможно, лучший ответ на ваш вопрос не имеет ничего общего с техническими деталями того, как поиск может быть выполненного в каждом продукте, но больше делать с простота использования для вашего конкретного случая использования. Очевидно, что вы смогли найти быстрый способ поиска с Solr с меньшими проблемами, чем PostgreSQL, и это может не привести ни к чему большему.

Я включаю краткий пример того, как текстовый поиск нескольких критериев может быть выполнен в PostgreSQL, и как несколько небольших настроек могут сделать большую разницу в производительности. Чтобы сохранить его быстро и просто, я просто бегу Война и мир в текстовой форме в тестовую базу данных, причем каждый "документ" представляет собой одну текстовую строку. Аналогичные методы можно использовать для произвольных полей с помощью hstore тип или JSON столбцы, если данные должны быть свободно определены. Там, где есть отдельные столбцы с собственными индексами, преимущества использования индексов, как правило, намного больше.

-- Create the table.
-- In reality, I would probably make tsv NOT NULL,
-- but I'm keeping the example simple...
CREATE TABLE war_and_peace
  (
    lineno serial PRIMARY KEY,
    linetext text NOT NULL,
    tsv tsvector
  );

-- Load from downloaded data into database.
COPY war_and_peace (linetext)
  FROM '/home/kgrittn/Downloads/war-and-peace.txt';

-- "Digest" data to lexemes.
UPDATE war_and_peace
  SET tsv = to_tsvector('english', linetext);

-- Index the lexemes using GiST.
-- To use GIN just replace "gist" below with "gin".
CREATE INDEX war_and_peace_tsv
  ON war_and_peace
  USING gist (tsv);

-- Make sure the database has statistics.
VACUUM ANALYZE war_and_peace;

после настройки для индексирования я показываю несколько поисков с подсчетами строк и таймингами с обоими типами индексов:

-- Find lines with "gentlemen".
EXPLAIN ANALYZE
SELECT * FROM war_and_peace
  WHERE tsv @@ to_tsquery('english', 'gentlemen');

84 строки, gist: 2.006 ms, Джин: 0.194 ms

-- Find lines with "ladies".
EXPLAIN ANALYZE
SELECT * FROM war_and_peace
  WHERE tsv @@ to_tsquery('english', 'ladies');

184 строки, gist: 3.549 ms, Джин: 0.328 МС

-- Find lines with "ladies" and "gentlemen".
EXPLAIN ANALYZE
SELECT * FROM war_and_peace
  WHERE tsv @@ to_tsquery('english', 'ladies & gentlemen');

1 ряд, gist: 0.971 ms, Джин: 0.104 ms

теперь, поскольку индекс Джина был примерно в 10 раз быстрее, чем индекс GiST, вы можете задаться вопросом, почему кто-то будет использовать GiST для индексирования текстовых данных. Ответ заключается в том, что GiST обычно быстрее поддерживать. Поэтому, если ваши текстовые данные сильно изменчивы, индекс GiST может выиграть при общей загрузке, в то время как индекс GIN выиграет, если вас интересует только время поиска или для чтения рабочая загрузка.

без индекса вышеуказанные запросы занимают от 17.943 мс до 23.397 МС, поскольку они должны сканировать всю таблицу и проверять соответствие в каждой строке.

Джин индексированный поиск строк с "дамами" и "джентльменами" более чем в 172 раза быстрее, чем сканирование таблицы в точно такой же базе данных. Очевидно, что преимущества индексации были бы более драматичными с большими документами, чем использовались для этого теста.

настройка, конечно, одноразовая вещь. С триггером для поддержания tsv столбец, любые внесенные изменения будут мгновенно доступны для поиска без повторной настройки.

с медленным запросом PostgreSQL, если вы показываете структуру таблицы (включая индексы), запрос проблемы и вывод из запуска EXPLAIN ANALYZE вашего запроса, кто-то почти всегда может определить проблему и предложить, как заставить ее работать быстрее.


обновление (9 декабря '16)

Я не упомянул, что я используется для получения предыдущих таймингов, но на основе даты, вероятно, это был бы основной выпуск 9.2. Я просто наткнулся на этот старый поток и попробовал его снова на том же оборудовании, используя версию 9.6.1, чтобы увидеть, помогает ли какая-либо промежуточная настройка производительности этому примеру. Запросы только для одного аргумента только увеличились в производительности примерно на 2%, но поиск строк с обоими "дамами"и "джентльмены" примерно удвоили скорость до 0,053 МС (т. е. 53 микросекунды), когда используя индекс Джина (инвертированный).


эта самая большая разница заключается в том, что индекс Lucene/Solr похож на базу данных с одной таблицей без поддержки реляционных запросов (соединений). Помните, что индекс обычно существует только для поддержки поиска и не является основным источником данных. Таким образом, ваша база данных может быть в "третьей нормальной форме", но индекс будет полностью де-нормализован и содержать в основном только данные, необходимые для поиска.

другая возможная причина, как правило, базы данных страдают от внутренних фрагментация, они должны выполнять слишком много полуслучайных задач ввода-вывода по огромным запросам.

Это означает, что, например, учитывая индексную архитектуру баз данных, запрос приводит к индексам, которые, в свою очередь, приводят к данным. Если данные для восстановления широко распространены, результат займет много времени, и это, похоже, происходит в базах данных.


Solr предназначен в первую очередь для поиска данных, а не для хранения. Это позволяет ему отказаться от большей части функций, требуемых от RDMS. Так оно (вернее введение) концентрируется на чисто индексирования данных.

Как вы, несомненно, обнаружили, Solr позволяет осуществлять поиск и извлечение данных из индекса. Это последняя (необязательная) возможность, которая приводит к естественному вопросу... - Могу я использовать Solr в качестве базы данных?"

ответ квалифицированный да, и я отсылаю вас к следующему:

мое личное мнение заключается в том, что Solr лучше всего рассматривать как кэш для поиска между моим приложением и данными, освоенными в моей базе данных. Так я получаю ... лучшее из обоих миров.


читайте этой и этой.

Solr (Lucene) создает инвертированный индекс где получение данных происходит довольно быстро. Я!--9-->читать что PostgreSQL также имеет аналогичное средство, но не уверен, что вы использовали это.

различия в производительности, которые вы наблюдали, также можно отнести к "что ищется ?", "каковы пользовательские запросы ?"