Я вообще не профессионал в SQL :) Имею очень критическую проблему с производительностью. Вот информация, непосредственно связанная с проблемой.
У меня есть 2 таблицы в моей DB- таблицы condos
и таблицы goods
.
В табличных condos
есть поля:
элементы таблицы:
У меня есть 1000+ объекты в condos
таблице и 1000+ в items
таблицы.
Проблема в том, как я выполняю поиск элементов
в настоящее время это:
Например, я хочу получить все предметы для city = Sydney
SELECT condos.condo_id FROM public.condos WHERE city = 'Sydney'
SELECT * FROM public.items WHERE item.condo_id =?
для каждого condo_id
я получаю на шаге 1. Проблема в том, что когда - то я получаю 1000+ объекты в condos
таблицы, запрос выполняется 1000+ раз для каждого condo_id
принадлежит "Сидней". И выполнение этого запроса занимает более 2 минут, что является критическим вопросом производительности.
Итак, вопросы:
Каков наилучший способ для меня выполнить такой поиск? Должен ли я поместить идентификатор 1000+ в один запрос WHERE
? или?
Для добавления информации я использую PostgreSQL 9.4 и Spring MVC.
По сути, вам нужно устранить запрос 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 запросов. Все три варианта - это решения.
WHERE
, я должен указать их в операторе AND
? например: and condos.city='Sydney' and item.name='item1' and item.price=1999
и т. д. (если я использую запрос JOIN)
Используйте таблицу 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
чтобы разработать план запроса для вашего запроса, есть ли полный поиск в таблице, который может вызвать проблемы с производительностью.
Надеюсь, это поможет.
Вы можете использовать первый запрос как подзапрос in
операторе in во втором запросе:
SELECT *
FROM public.items
WHERE item.condo_id IN (SELECT condos.condo_id
FROM public.condos
WHERE city = 'Sydney')