Проблема производительности в сочетании, где пункты - PullRequest
1 голос
/ 31 мая 2019

Вопрос

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

Поиск

Я выполняю поиск для наших пользователей, им предоставляется возможность поиска кандидатов в нашей системе на основе:

  • Профессиональная группа, в которую они попадают,
  • Местоположение + радиус,
  • Полнотекстовый поиск.

Запрос

select v.id
    from (
        select
            c.id,
            c.ts_description,
            c.latitude,
            c.longitude,
            g.group
        from entities.candidates c
        join entities.candidates_connections cc on cc.candidates_id = c.id
        join system.groups g on cc.systems_id = g.id
    ) v

    -- Group selection
    where v.group = 'medical'

    -- Location + radius
    and earth_distance(ll_to_earth(v.latitude, v.longitude), ll_to_earth(50.87050439999999, -1.2191283)) < 48270

    -- Full text search
    and v.ts_description @@ to_tsquery('simple', 'nurse | doctor')
;

Размер данных и ориентиры

Я работаю с 1,7 миллионами записей

У меня есть 3 условия в порядке удара, которые были сопоставлены в изоляции:

  • Групповое предложение: 3 с и уменьшает до 700 тыс. Записей
  • Положение о местоположении: 8 с и уменьшает до 54k записей
  • Полнотекстовое предложение: 60 с + и сокращение до 10 тыс. Записей

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

Что я пробовал

  • Все условия соединения и где индексируются пункты
  • В частности, индекс ts_description (GIN) составляет 2 ГБ
  • широта / широта индексируется с помощью ll_to_earth () для уменьшения влияния на строку
  • Я вложил каждый оператор where в отдельный подзапрос в порядке
  • Изменен порядок всех пунктов и подзапросов
  • Увеличен размер shared_buffers для увеличения потенциальных попаданий в кеш

Ответы [ 2 ]

0 голосов
/ 11 июня 2019

Были некоторые примеры наилучшей практики, которые я не рассматривал, я впоследствии реализовал их, чтобы получить существенное увеличение производительности:

Уменьшение размера индекса tsvector

Iв tsvector хранилось до 25 000 символов, это означало, что когда использовались более сложные полнотекстовые поисковые запросы, было просто огромное количество работы, я сократил ее до 10 000, что имело большое значение и для моего случая использованияэто приемлемый компромисс.

Создание материализованного представления

Я создал материализованное представление, содержащее объединение, это снимает с себя небольшую часть работы, дополнительно я создал там свои индексы и запустилодновременное обновление с интервалом в 2 часа.Это дает мне довольно стабильную таблицу для работы.

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

Увеличение ОЗУ и использование pg_prewarm

Я увеличил ОЗУ сервера, чтобы дать мнедостаточно места для хранения моего материализованного представления, а затем запустил pg_prewarm в моем материализованном представлении.Хранение в памяти дало мне самое большое увеличение производительности, снизив 2-метровый запрос до 3 с.

0 голосов
/ 31 мая 2019

Кажется, что вам не нужно подзапросов, и также рекомендуется фильтровать по числовым полям, поэтому вместо фильтрации, например, с помощью where v.group = 'medical', создайте словарь и просто отфильтруйте с помощью where v.group = 1

        select
            DISTINCT c.id,
        from entities.candidates c
        join entities.candidates_connections cc on cc.candidates_id = c.id
        join system.groups g on cc.systems_id = g.id
    where tablename.group = 1
    and earth_distance(ll_to_earth(v.latitude, v.longitude), ll_to_earth(50.87050439999999, -1.2191283)) < 48270
    and v.ts_description @@ to_tsquery(0, 1 | 2)

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...