我有这个查询:
select
a.*,
trunc(MAX(rebase.circulating_supply) * a.supply_percentage, 9) as ampl_balance,
trunc(
MAX(rebase.circulating_supply) *
(coalesce(SUM(t.supply_percentage) FILTER (WHERE t.to = a.contract_address), 0) +
(coalesce(SUM(t.supply_percentage) FILTER (WHERE t.from = a.contract_address), 0) * -1)),
9
) as net_ampl_moved
from addresses as a
cross join (select r.circulating_supply from rebases r order by r.timestamp desc limit 1) as rebase
left join transfers as t
on (t.from = a.contract_address or t.to = a.contract_address) and t.timestamp >= ?
group by a.contract_address;
此处的目标是汇总某个时间段内账户的净余额,例如从过去 24 小时开始,所有时间等等。我通过总结每笔交易和每笔交易来做到这一点。
转移索引:
CREATE INDEX transfers_from_to_index ON public.transfers USING btree ("from", "to")
CREATE INDEX transfers_timestamp_index ON public.transfers USING btree ("timestamp")
CREATE INDEX transfers_action_index ON public.transfers USING btree (action)
CREATE UNIQUE INDEX transfers_pkey ON public.transfers USING btree (transaction_hash, log_index)
CREATE INDEX transfers_supply_percentage_index ON public.transfers USING btree (supply_percentage)
CREATE INDEX transfers_amount_index ON public.transfers USING btree (amount)
CREATE INDEX transfers_supply_percentage_timestamp_log_index_index ON public.transfers USING btree (supply_percentage, "timestamp", log_index)
CREATE INDEX transfers_from_index ON public.transfers USING btree ("from")
CREATE INDEX transfers_to_index ON public.transfers USING btree ("to")
地址索引:
CREATE UNIQUE INDEX addresses_pkey ON public.addresses USING btree (contract_address)
CREATE INDEX addresses_supply_percentage_index ON public.addresses USING btree (supply_percentage)
rebase 上的索引:
CREATE UNIQUE INDEX rebases_pkey ON public.rebases USING btree (epoch)
CREATE INDEX rebases_timestamp_index ON public.rebases USING btree ("timestamp")
解释计划:
https://explain.depesz.com/s/1Zy
这里的任何帮助将不胜感激。
答案 0 :(得分:1)
transfers
上的左连接是成本最高的部分,主要是由于 OR
并且没有好的索引来解决它。
Mybe 试试这个?
select
a.*,
trunc(
MAX(rebase.circulating_supply)
* a.supply_percentage,
9
) as ampl_balance,
trunc(
MAX(rebase.circulating_supply)
* coalesce(SUM(t.supply_percentage), 0),
9
) as net_ampl_moved
from addresses as a
cross join (select r.circulating_supply from rebases r order by r.timestamp desc limit 1) as rebase
left join (
select tt.to as contract_address, tt.timestamp, tt.supply_percentage from transfers tt
union all
select tf.from as contract_address, tf.timestamp, -tf.supply_percentage from transfers tf
) t
on t.contract_address = a.contract_address and t.timestamp >= ?
group by a.contract_address;
然后在transfers
中有两个新索引...
CREATE INDEX transfers_to_timestamp_index
ON public.transfers
USING btree ("to", "timestamp")
INCLUDE ("supply_percentage");
CREATE INDEX transfers_from_timestamp_index
ON public.transfers
USING btree ("from", "timestamp")
INCLUDE ("supply_percentage");
这应该会使连接和聚合都更便宜。
编辑:另一种选择...
使用与上面提到的相同的索引,但将所有聚合折叠到仅传输表上的子查询中。
(并将子查询移至 CTE 以提高可读性...)
WITH
t_normalised
AS
(
select tt.to as contract_address, tt.timestamp, tt.supply_percentage from transfers tt
union all
select tf.from as contract_address, tf.timestamp, -tf.supply_percentage from transfers tf
),
t_sum
AS
(
SELECT
contract_address,
SUM(supply_percentage) AS supply_percentage
FROM
t_normalised
WHERE
timestamp >= ?
GROUP BY
contract_address
),
rebase
AS
(
select r.circulating_supply
from rebases r
order by r.timestamp desc
limit 1
)
select
a.*,
trunc(
rebase.circulating_supply
* a.supply_percentage,
9
) as ampl_balance,
trunc(
rebase.circulating_supply
* coalesce(t_sum.supply_percentage, 0),
9
) as net_ampl_moved
from
addresses as a
cross join
rebase
left join
t_sum
on t_sum.contract_address = a.contract_address