Reputation: 1876
I'm looking for a way to save some calculation from being done twice in a query like:
SELECT DISTINCT
coins.price_btc,
coins.price_eur,
coins.price_usd,
coins.currency_name,
coins.currency_symbol,
SUM ( market_transactions.quantity ) OVER ( PARTITION BY market_transactions.market_coin_id ) * coins.price_eur AS holdings_eur,
SUM ( market_transactions.quantity ) OVER ( PARTITION BY market_transactions.market_coin_id ) * coins.price_usd AS holdings_usd,
SUM ( market_transactions.quantity ) OVER ( PARTITION BY market_transactions.market_coin_id ) * coins.price_btc AS holdings_btc,
SUM ( market_transactions.quantity ) OVER ( PARTITION BY market_transactions.market_coin_id ) AS holdings
FROM
market_transactions
INNER JOIN coins ON coins.id = market_transactions.market_coin_id
WHERE
market_transactions.user_id = 1
ORDER BY
coins.currency_symbol
I'm not sure if that sum over partition is running all these times.
Thanks for any pointers, I'm sure the query can also be optimized but I'm unsure where to start.
CREATE TABLE "public"."coins" (
"id" int8 NOT NULL DEFAULT nextval('coins_id_seq'::regclass),
"currency_symbol" text COLLATE "pg_catalog"."default" NOT NULL DEFAULT NULL,
"currency_name" text COLLATE "pg_catalog"."default" NOT NULL DEFAULT NULL,
"price_usd" numeric(16,7) NOT NULL DEFAULT NULL,
"price_eur" numeric(16,7) NOT NULL DEFAULT NULL,
"price_btc" numeric(16,7) NOT NULL DEFAULT NULL,
CONSTRAINT "coins_pkey" PRIMARY KEY ("id")
)
CREATE TABLE "public"."market_transactions" (
"id" int8 NOT NULL DEFAULT nextval('market_transactions_id_seq'::regclass),
"user_id" int4 NOT NULL DEFAULT NULL,
"quantity" numeric(18,8) NOT NULL DEFAULT NULL,
"market_coin_id" int4 DEFAULT NULL,
CONSTRAINT "market_transactions_pkey" PRIMARY KEY ("id")
)
A user has many transactions involving a coin (market_transactions.market_coin_id
is coins.id
), I'm trying to SUM the quantity owned (market_transactions.quantity
) for each one and then multiply this value for the price of the coin expressed in different currencies (btc, eur, usd)
Upvotes: 0
Views: 138
Reputation: 1269445
I would suggest aggregating before join
ing and doing:
SELECT c.*,
mt.quantity * c.price_eur AS holdings_eur,
mt.quantity * c.price_usd AS holdings_usd,
mt.quantity * c.price_btc AS holdings_btc,
mt.quantity * c.market_coin_id AS holdings
FROM coins c JOIN
(SELECT mt.market_coin_id, SUM(mt.quantity) as quantity
FROM market_transactions t
WHERE mt.user_id = 1
GROUP BY mt.market_coin_id
) mt
ON c.id = mt.market_coin_id
ORDER BY c.currency_symbol
Upvotes: 1
Reputation: 3823
Run an EXPLAIN (i.e. EXPLAIN SELECT DISTINCT ...) on the query and see what the query plan is. Most likely, it's only running the window function once. If it is running it multiple times, try adding an outer SELECT:
SELECT DISTINCT
price_btc,
price_eur,
price_usd,
currency_name,
currency_symbol,
holdings * price_eur AS holdings_eur,
holdings * price_usd AS holdings_usd,
holdings * price_btc AS holdings_btc,
holdings
FROM (
SELECT
coins.price_btc,
coins.price_eur,
coins.price_usd,
coins.currency_name,
coins.currency_symbol,
SUM ( market_transactions.quantity ) OVER ( PARTITION BY market_transactions.market_coin_id ) AS holdings
FROM
market_transactions
INNER JOIN coins ON coins.id = market_transactions.market_coin_id
WHERE
market_transactions.user_id = 1
) src
ORDER BY
currency_symbol
Upvotes: 1