результата groupwise maximum?
Есть таблицы...
temp=# \d users_balances
Table "public.users_balances"
Column | Type | Collation | Nullable | Default
-------------+--------------------------+-----------+----------+---------
user_id | integer | | |
currency | text | | |
timestamp | timestamp with time zone | | |
balance | numeric(32,0) | | |
is_verified | boolean | | |
Indexes:
"users_balances_user_id_currency_timestamp_idx" btree (user_id, currency, "timestamp") WHERE is_verified = true
temp=# \d users_currencies
Table "public.users_balances"
Column | Type | Collation | Nullable | Default
-------------+--------------------------+-----------+----------+---------
user_id | integer | | |
currency | text | | |
Indexes:
"users_currencies_pkey" PRIMARY KEY, btree (user_id, currency)
"users_currencies_currency_idx" btree (currency)
...и тестовые данные к ним:
temp =# INSERT INTO users_balances VALUES
(1, 'USD', '2019-11-20 16:38:10.646554+00', 100, true),
(1, 'EUR', '2019-11-20 16:38:11.646554+00', 100, true),
(1, 'USD', '2019-11-20 16:38:12.646554+00', 200, false),
(1, 'USD', '2019-11-20 16:38:13.646554+00', 300, true),
(2, 'USD', '2019-11-20 16:38:14.646554+00', 100, true),
(3, 'RUB', '2019-11-20 16:38:15.646554+00', 100, true);
INSERT 0 6
temp =# INSERT INTO users_currencies VALUES
(1, 'USD'),
(1, 'EUR'),
(2, 'USD'),
(3, 'RUB');
INSERT 0 4
Задача в том, чтобы получить пользователей для какой-то валюты отсортированными по балансу. Текущий запрос:
SELECT uc.user_id, uc.currency, x.balance
FROM users_currencies AS uc
CROSS JOIN LATERAL (
SELECT ub.balance
FROM users_balances AS ub
WHERE ub.user_id = uc.user_id AND ub.currency = uc.currency
AND ub.is_verified
ORDER BY ub.timestamp DESC
LIMIT 1
) AS x
WHERE uc.currency = 'USD'
ORDER BY x.balance DESC LIMIT 20;
Но его перформанс не устраивает, если пользователей валюты много (800к). План для куска данных:
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------------
Limit (cost=10709206.51..10709206.56 rows=20 width=102)
-> Sort (cost=10709206.51..10712184.89 rows=1191351 width=102)
Sort Key: ub.balance DESC
-> Nested Loop (cost=0.69..10677505.09 rows=1191351 width=102)
-> Seq Scan on users_currencies uc (cost=0.00..277010.86 rows=1191351 width=86)
Filter: ((currency)::text = 'USD'::text)
-> Limit (cost=0.69..8.71 rows=1 width=12)
-> Index Scan Backward using users_balances_user_id_currency_timestamp_idx on user_balances ub (cost=0.69..8.71 rows=1 width=12)
Index Cond: (((currency)::text = (uc.currency)::text) AND ((user_id)::text = (uc.user_id)::text))
Вообще, тут почему-то два раза показана: Table "public.users_balances" Но посыл понятен. ;) И такие планы, в общем, бесполезны — всегда показывайте EXPLAIN (ANALYZE, BUFFERS), если есть возможность.
Обсуждают сегодня