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

Недавно я переключился с Postgres на Solr и увидел, что наши запросы ускоряются примерно в 50 раз. Запросы, которые мы выполняем, включают несколько диапазонов, и наши данные - это списки транспортных средств. Например: & quot; Найти все автомобили с пробегом & lt; 50000, 5000 долларов & lt; цена & lt; $ 10000, сделать = Mazda ... & quot;

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

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

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

 a_horse_with_no_name07 апр. 2012 г., 11:36
Вы использовали полнотекстовый поиск Postgres или простойLIKE запросы?
 alfonx02 февр. 2013 г., 14:07
Я немного смущен вашим вопросом, поэтому я спрашиваю здесь:dba.stackexchange.com/questions/34014/… Будет ли поиск в Solr / Lucene быстрее, чем в PostgreSQL, даже если полнотекстовый поиск не задействован?
 wildplasser07 апр. 2012 г., 14:44
Реляционная модель никогда не предназначалась для эффективной работы с такими уродливыми запросами, какgive me all the people who were born on a wednesday and owned a red car between 2003 and 2005, Для этого есть поисковые системы (такие как Lucene). Индексы иногда помогают, настройки памяти всегда помогают.
 vonPetrushev24 июн. 2013 г., 18:50
Если был загруженный вопрос - это оно. Могу поспорить, что вы даже не рассматривали возможность использования каких-либо частичных индексов.
 kgrittn26 авг. 2013 г., 22:43
Что это была за версия PostgreSQL? Если все столбцы были проиндексированы, я бы удивился, что он не использовал сканирование растровых индексов, если только вы не использовали очень старую версию PostgreSQL или ваша статистика не была обновлена. Когда он использует такой план, он сканирует несколько индексов для диапазонов значений, формируя растровое изображение расположения строк, затем применяет логическую логику к растровым изображениям и извлекает только совпадающие строки в порядке расположения (для оптимизации доступа к диску).

Ответы на вопрос(5)

Решение Вопроса

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

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

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

 07 апр. 2012 г., 14:07
Когда новый SegmentReader (IndexReader для одного сегмента) открыт, он загружает по умолчанию каждый (n * 16) -й член индекса в массиве Java в памяти (16 - этоindexDivisor). Затем поиск выполняется с помощью бинарного поиска в памяти по этому массиву, затем один поиск на диске и не более 15 терминов сравнения на диске. Таким образом, общая стоимостьO(log(t/16)) + O(1) + O(15) = O(log(t)).
 07 апр. 2012 г., 14:06
Нет необходимости в балансовом дереве, так как данные никогда не нужно обновлять. Когда данные добавляются в индекс Lucene, создается новый сегмент. Этот сегмент имеет приоритет над предыдущими сегментами. Когда сегментов слишком много, MergeScheduler выбирает сегменты для объединения в соответствии с MergePolicy (это имена классов в Lucene).
 07 апр. 2012 г., 13:35
Отличный ответ (первый абзац) +1.
 07 апр. 2012 г., 13:56
Здесь следует добавить еще одну вещь: даже если Lucene Index не является BTree, он, однако, инвертированный (как и большинство поисковых систем). Ваш ответ, однако, пришел как нечто новое для меня. Как я и ожидал, структура сбалансированного дерева будет хранить термины (в этом случае поиск также будет log (t), и каждый узел также будет содержать указатель на списки публикаций. С деревьями баланса мы даже сможем поддерживать лексикографически отсортированные термины.
 07 апр. 2012 г., 13:51
Хотя мне есть что сказать здесь. Когда вы говорите, «Lucene поддерживает словарь терминов, который состоит из списка терминов, которые появляются в сегменте, отсортированы по лексикографическому признаку». Так что, если термины лексикографически отсортированы & amp; это занимает o (log t) время (бинарный поиск), что означает, что термины хранятся в массиве? Правильно ли это (я имею в виду, что вы отказались от сбалансированной древовидной структуры для хранения индексов и хеш-таблицы не могут хранить сразу отсортированные индексы, поэтому у нас остается только двумерный массив (с термином, указателем на список публикаций в качестве его элементов), в котором используется двоичный поиск ведется)

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

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

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

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

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

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

https://stackoverflow.com/questions/5814050/solr-or-database Using Solr search index as a database - is this "wrong"? For the guardian solr is the new database

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

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

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

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

 07 апр. 2012 г., 14:28
Явар: Я не говорил, что базы данных не могут создавать инвертированные индексы. Фактически во 2-й строке я указал на ссылку о PostgreSQL, используя GIN-инвертированный индекс. Существует другой тип: индекс на основе GiST (обобщенного дерева поиска) в PostgreSQL, который МЕНЬШЕ, чем GIN. Фактический тип индекса, используемый @cberner, будет одним из факторов низкой производительности PostgreSQL.
 07 апр. 2012 г., 12:21
@ Tejas: даже базы данных могут создавать инвертированные индексы. Что мешает им создать инвертированные индексы?
 cberner07 апр. 2012 г., 11:16
Спасибо! Это было очень интересно. Хотя я надеялся на что-то более техническое. Например, обзор архитектуры Solr или что-то в этом роде.

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

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

Возможно, лучший ответ на ваш вопрос не имеет ничего общего с техническими деталями того, как может быть выполнен поиск.performed в каждом продукте, но больше связано сease of use для вашего конкретного случая использования. Очевидно, что вы смогли найти быстрый способ поиска с 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 строки, суть: 2,006 мс, джин: 0,194 мс

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

184 строки, суть: 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 строка, суть: 0,971 мс, джин: 0,104 мс

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

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

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

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

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

UPDATE (9 и 16 декабря)

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

 31 мар. 2015 г., 13:42
Обратите внимание, что GiST больше не так быстро поддерживать, ср.blog.pgaddict.com/posts/…

Ваш ответ на вопрос