Дан SQL-запрос и схема: таблицы Orders(order_id, customer_id, amount), Customers(customer_id, country). Как написать запрос, который возвращает среднюю сумму заказа по стране, игнорируя выбросы и учитывая масштабируемость при миллионах строк?

23 Мар в 09:40
17 +1
0
Ответы
1
Идея: для каждой страны вычислить пороги выбросов (например, исключить нижние и верхние 1%1\%1%: пороги p0.01p_{0.01}p0.01 и p0.99p_{0.99}p0.99 ), затем посчитать среднее по заказам, попавшим в этот интервал. Ниже — два варианта: точный (PostgreSQL) и масштабируемый/приблизительный (BigQuery / аналитические СУБД).
1) PostgreSQL (точно, но затратнее):
```
WITH country_bounds AS (
SELECT c.country,
percentile_cont(0.01) WITHIN GROUP (ORDER BY o.amount) AS p_low,
percentile_cont(0.99) WITHIN GROUP (ORDER BY o.amount) AS p_high
FROM Orders o
JOIN Customers c USING (customer_id)
GROUP BY c.country
)
SELECT cb.country,
AVG(o.amount) AS avg_trimmed
FROM Orders o
JOIN Customers c USING (customer_id)
JOIN country_bounds cb USING (country)
WHERE o.amount BETWEEN cb.p_low AND cb.p_high
GROUP BY cb.country;
```
Здесь пороги соответствуют долям 0.010.010.01 и 0.990.990.99.
2) Масштабируемо / приближённо (BigQuery пример, быстрее на больших данных):
```
WITH percentiles AS (
SELECT country,
(SELECT quantiles[OFFSET(1)] FROM UNNEST(APPROX_QUANTILES(amount, 100)) AS quantiles) AS p_low,
(SELECT quantiles[OFFSET(99)] FROM UNNEST(APPROX_QUANTILES(amount, 100)) AS quantiles) AS p_high
FROM Orders o
JOIN Customers c USING(customer_id)
GROUP BY country
)
SELECT p.country,
AVG(o.amount) AS avg_trimmed
FROM Orders o
JOIN Customers c USING(customer_id)
JOIN percentiles p USING(country)
WHERE o.amount BETWEEN p.p_low AND p.p_high
GROUP BY p.country;
```
Здесь используется приближённая функция, дающая пороги для примерно 1%1\%1% и 99%99\%99%.
Короткие рекомендации по масштабируемости:
- Вычисление порогов делать отдельной агрегацией (один проход по данным), затем JOIN и второй проход для усреднения — это две простые агрегации, хорошо масштабируются.
- На больших объёмах используйте встроенные приближённые агрегаты (tdigest/approx_percentile/APPROX_QUANTILES).
- Индекс/партиционирование по customer_id или country и по amount ускорит группы и фильтры.
- Выберите уровень отсечения α\alphaα (например, α=0.01\alpha = 0.01α=0.01) в зависимости от задачи.
23 Мар в 09:47
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Гарантированные бесплатные доработки в течение 1 года
Быстрое выполнение от 2 часов
Проверка работы на плагиат
Поможем написать учебную работу
Прямой эфир