Простой запрос очень медленный - PullRequest
2 голосов
/ 16 марта 2020

У меня есть этот запрос, для выполнения которого требуется 36 с, и я не понимаю, почему и как я могу его улучшить. Любая помощь?

SELECT p.* FROM products p INNER JOIN product_store ps ON p.id = ps.product_id
INNER JOIN stores s ON s.id = ps.store_id WHERE s.city = 'Berlin' GROUP BY p.id LIMIT 16 OFFSET 0;

Это следующие цифры:

SELECT count(*) FROM products;

43309

SELECT count(*) FROM product_store;

1456445

SELECT count(*) FROM stores;

155

Я полагаю, что это может быть для таблицы отношений, но 36 с - это слишком много для 16 строк.

Есть идеи, как улучшить этот запрос?

РЕДАКТИРОВАТЬ:

По любой причине проблема не в Postgres, а в Hibernate. Запрос довольно быстрый в pgAdmin 4, но очень медленный в Hibernate.

Спасибо всем!

РЕДАКТИРОВАТЬ 2:

Анализ

analysis

РЕДАКТИРОВАТЬ 3:

Извините, это реальная проблема, когда я добавляю "DISTINCT"

SELECT DISTINCT p.* FROM products p INNER JOIN product_store ps ON p.id = ps.product_id
INNER JOIN stores s ON s.id = ps.store_id WHERE s.city = 'Berlin' GROUP BY p.id LIMIT 16 OFFSET 0;

ПРОИЗВОДСТВО analyze

МЕСТНЫЙ analyze

Ответы [ 2 ]

3 голосов
/ 16 марта 2020

Агрегация - большая проблема. Я бы предложил использовать EXISTS вместо:

SELECT p.*
FROM products p 
WHERE EXISTS (SELECT 1
              FROM product_store ps INNER JOIN
                   stores s 
                   ON s.id = ps.store_id
              WHERE p.id = ps.product_id AND s.city = 'Berlin' 
             )
LIMIT 16 OFFSET 0;

Тогда убедитесь, что у вас есть индексы на product_store(product_id, store_id). Я предполагаю, что у вас уже есть индекс на stores(id) - потому что это должен быть первичный ключ.

1 голос
/ 16 марта 2020

Я бы предложил использовать IN вместо этого, поскольку селективный предикат находится в подзапросе. Лучше использовать EXISTS, если избирательный предикат находится в родительском запросе. При использовании IN оптимизатор записывает подзапрос в представление, а затем присоединяется к таблице products через уникальный индекс. Пожалуйста, проверьте планы выполнения, используя EXISTS и IN, чтобы увидеть разницу.

SELECT p.*
FROM products p 
WHERE p.id IN (SELECT ps.product_id
              FROM product_store ps 
              JOIN stores s ON s.id = ps.store_id
              WHERE p.id = ps.product_id AND s.city = 'Berlin' 
             )
LIMIT 16 OFFSET 0;
...