PostgreSQL многократный запрос "ГДЕ" (1000+)

2

Я вообще не профессионал в SQL :) Имею очень критическую проблему с производительностью. Вот информация, непосредственно связанная с проблемой.

У меня есть 2 таблицы в моей DB- таблицы condos и таблицы goods.

В табличных condos есть поля:

  • id (PK)
  • имя
  • город
  • страна

элементы таблицы:

  • id (PK)
  • имя
  • несколько полей, не связанных с проблемой
  • condo_id (FK)

У меня есть 1000+ объекты в condos таблице и 1000+ в items таблицы.

Проблема в том, как я выполняю поиск элементов

в настоящее время это:

Например, я хочу получить все предметы для city = Sydney

  1. Выполните SELECT condos.condo_id FROM public.condos WHERE city = 'Sydney'
  2. Сделать SELECT * FROM public.items WHERE item.condo_id =? для каждого condo_id я получаю на шаге 1.

Проблема в том, что когда - то я получаю 1000+ объекты в condos таблицы, запрос выполняется 1000+ раз для каждого condo_id принадлежит "Сидней". И выполнение этого запроса занимает более 2 минут, что является критическим вопросом производительности.

Итак, вопросы:

Каков наилучший способ для меня выполнить такой поиск? Должен ли я поместить идентификатор 1000+ в один запрос WHERE? или?

Для добавления информации я использую PostgreSQL 9.4 и Spring MVC.

  • 4
    Область, которую вы знаете о таблицах? Из твоего вопроса кажется, что это не так, и если нет, тебе нужно узнать о них. Это как раз та проблема, которую объединение должно решить.
Теги:
database

3 ответа

1
Лучший ответ

По сути, вам нужно устранить запрос N + 1 и в то же время обеспечить, чтобы ваше поле города было проиндексировано. У вас есть 3 механизма. Один из них уже указан в одном из других ответов, которые вы получили, это подход SUBSELECT. Помимо этого подхода у вас есть еще два.

Вы можете использовать то, что вы заявили:

SELECT condos.condo_id FROM public.condos WHERE city = 'Sydney'

SELECT * 
FROM   public.items 
WHERE  items.condo_id IN (up to 1000 ids here) 

причина, по которой я заявляю до 1000, заключается в том, что некоторые поставщики SQL имеют ограничения.

Вы также можете объединиться, чтобы устранить выбор N + 1

SELECT * 
FROM   public.items join  public.condos on items.condo_id=condos.condo_id  and condos.city='Sydney'

Теперь в чем разница между тремя запросами.

Плюсы запроса Subselect - это то, что вы получаете все сразу. Недостаток заключается в том, что если у вас слишком много элементов, производительность может пострадать:

Плюсы простого предложения In. Эффективно решает проблему N + 1, Минусы могут привести к некоторым дополнительным запросам по сравнению с Subselect

Присоединившиеся профили запроса, вы можете инициализировать за один раз оба Кондо и Элемент. Минусы приводят к дублированию данных на стороне Кондо

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

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

Эффективно все, что решает вашу проблему с запросом N + 1, является решением в вашем случае, если мы говорим всего за 2 раза 1000 запросов. Все три варианта - это решения.

  • 0
    спасибо вот самый полный ответ. Еще один маленький вопрос - если у меня есть несколько параметров WHERE , я должен указать их в операторе AND ? например: and condos.city='Sydney' and item.name='item1' and item.price=1999 и т. д. (если я использую запрос JOIN)
  • 0
    Теоретически вы можете поместить их прямо в предложение join или после предложения where. Я знаю, что для разных поставщиков БД может быть небольшая разница в производительности, но вы должны проверить это самостоятельно. Так что да, либо вы указываете их с условиями AND в предложении where, либо вы помещаете их прямо в предложение JOIN снова с помощью AND.
Показать ещё 6 комментариев
2

Используйте таблицу join, чтобы выполнить запрос таким образом, что вам не нужно, чтобы выполнить дополнительный запрос. В вашем случае вы можете присоединиться к condos и items condo_id что-то вроде:

SELECT i.* 
FROM public.items i join public.condos c on i.condo_id = c.condo_id 
WHERE c.city = 'Sydney'  

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

Вот еще одно предложение, которое также может помочь:

Попытайтесь добавить индекс в поле, где вы используете сортировку и поиск, например, city в condos и condo_id в items. Существует хороший ответ, чтобы объяснить, как работает индексирование.

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

Надеюсь, это поможет.

  • 0
    Это не сильно связано с вопросом, кроме части соединения.
  • 0
    @SamiKuhmonen OP сказал, что у него критическая проблема с производительностью, и выполнение запроса занимает более 2 минут. Поэтому я даю предложение о том, как лучше решить эту проблему. Я что-то пропустил?
0

Вы можете использовать первый запрос как подзапрос in операторе in во втором запросе:

SELECT * 
FROM   public.items 
WHERE  item.condo_id IN (SELECT condos.condo_id 
                         FROM   public.condos
                         WHERE  city = 'Sydney')

Ещё вопросы

Сообщество Overcoder
Наверх
Меню