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

Недавно я переключился с Postgres на Solr и увидел в наших запросах ~ 50 раз. Запросы, которые мы запускаем, включают несколько диапазонов, а наши данные - списки транспортных средств. Например: "Найти все транспортные средства с пробегом < 50,000, $5000 < цена < 10 000 $, make = Mazda..."

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

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

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

Ответ 1

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

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

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

Ответ 2

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

Только на этой неделе был отчет на работе, который кто-то написал с использованием Java и нескольких запросов таким образом, который, основываясь на том, как далеко он заработал за четыре часа, должен был пройти примерно месяц. (Ему нужно было поразить пять разных таблиц, каждая из которых содержит сотни миллионов строк.) Я переписал его, используя несколько CTE и функцию окна, чтобы она работала менее десяти минут и генерировала желаемые результаты прямо из запроса. Это 4400x ускорить.

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

Я включаю в себя краткий пример того, как текстовые запросы для нескольких критериев могут быть выполнены в PostgreSQL, и как несколько небольших настроек могут сильно повлиять на производительность. Чтобы это было быстро и просто, я просто запускаю War and Peace в текстовой форме в тестовую базу данных, причем каждый "документ" является единственной текстовой строкой. Подобные методы могут использоваться для произвольных полей, используя столбцы 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, gin: 0.194 ms

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

184 строки, gist: 3,549 мс, дин: 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 мс, дин: 0,104 мс

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

Без индекса вышеуказанные запросы берутся от 17,943 мс до 23,397 мс, так как они должны сканировать всю таблицу и проверять соответствие для каждой строки.

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

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

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


ОБНОВЛЕНИЕ (декабрь 9 '16)

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

Ответ 3

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

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

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

Ответ 4

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

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

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

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

Ответ 5

Пожалуйста, прочитайте этот и .

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

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