SQL: Как объединить таблицы с 1 миллионами записей

#sql #postgresql #performance #join #indexing

#sql #postgresql #Производительность #Присоединиться #индексирование

Вопрос:

Я хочу объединить две таблицы (таблица «продукты» содержит 1,5 миллиона записей), используя следующий запрос, но через 15 минут запрос все еще выполнялся, и мой компьютер перегревался (это lenovo v330-14ikb с 8 ГБ оперативной памяти), поэтому я остановил его.

Я очень новичок в индексах, и я попытался создать следующее:

  • СОЗДАЙТЕ ИНДЕКС customer_id_idx1 ДЛЯ заказов (customer_id)
  • СОЗДАЙТЕ ИНДЕКС customer_id_idx2 ДЛЯ продуктов (customer_id)
  • СОЗДАЙТЕ ИНДЕКС customer_id_revenues_idx ДЛЯ заказов (customer_id, доходы)
  • СОЗДАЙТЕ ИНДЕКС customer_id_costs_idx ДЛЯ продуктов (customer_id, затраты)

Это запрос:

 SELECT a.customer_id, (SUM(a.revenues) / SUM(b.costs) :: FLOAT) AS roi
FROM orders a
JOIN products b
ON a.customer_id = b.customer_id
WHERE a.customer_id IN (
    SELECT customer_id FROM (SELECT 
        customer_id,
        COUNT(*) AS n_products
    FROM products
    GROUP BY 1
    ORDER BY 2 DESC
    LIMIT 5) x
)
GROUP BY a.customer_id  
ORDER BY roi DESC
 

Выходные данные должны возвращать соотношение доходов / затрат для 5 лучших клиентов по количеству купленных ими продуктов.

Я использую pgadmin. Может кто-нибудь объяснить мне, как ускорить и заставить его скомпилироваться? Заранее благодарю вас.

Ответ №1:

Я не думаю, что вам нужно агрегировать дважды, насколько я могу судить.

 select customer_id, roi
from (
  select o.customer_id, 
         sum(o.revenues) / sum(p.costs)::float as roi, 
         count(*) as n_products
  from orders o
    join products p on o.customer_id = p.customer_id
  group by o.customer_id  
  order by n_products
  limit 5
) t
order by roi desc
 

В качестве альтернативы попробуйте объединить две таблицы по отдельности, а затем объединить результаты:

 select o.customer_id, o.revenues / p.costs::numeric as roi
from (
  select customer_id, sum(revenues) as revenues
  from orders
  group by customer_id
) o
  join (
    select customer_id, sum(costs) as costs, count(*) n_products
    from products
    group by customer_id
  ) p on p.customer_id = o.customer_id
order by p.n_products desc
limit 5