Skip to content

Commit 72f72a8

Browse files
authored
perf: force index usage in api/v2/addresses/:hash/transactions (blockscout#12415)
1 parent 8e36c75 commit 72f72a8

File tree

2 files changed

+59
-27
lines changed

2 files changed

+59
-27
lines changed

apps/block_scout_web/lib/block_scout_web/paging_helper.ex

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -292,8 +292,22 @@ defmodule BlockScoutWeb.PagingHelper do
292292

293293
def address_transactions_sorting(_), do: []
294294

295-
defp do_address_transaction_sorting("block_number", "asc"), do: [asc: :block_number, asc: :index]
296-
defp do_address_transaction_sorting("block_number", "desc"), do: [desc: :block_number, desc: :index]
295+
defp do_address_transaction_sorting("block_number", "asc"),
296+
do: [
297+
asc: :block_number,
298+
asc: :index,
299+
asc: :inserted_at,
300+
desc: :hash
301+
]
302+
303+
defp do_address_transaction_sorting("block_number", "desc"),
304+
do: [
305+
desc: :block_number,
306+
desc: :index,
307+
desc: :inserted_at,
308+
asc: :hash
309+
]
310+
297311
defp do_address_transaction_sorting("value", "asc"), do: [asc: :value]
298312
defp do_address_transaction_sorting("value", "desc"), do: [desc: :value]
299313
defp do_address_transaction_sorting("fee", "asc"), do: [{:dynamic, :fee, :asc_nulls_first, Transaction.dynamic_fee()}]

apps/explorer/lib/explorer/chain/transaction.ex

Lines changed: 43 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1124,7 +1124,9 @@ defmodule Explorer.Chain.Transaction do
11241124
Produces a list of queries starting from the given one and adding filters for
11251125
transactions that are linked to the given address_hash through a direction.
11261126
"""
1127-
def matching_address_queries_list(query, :from, address_hashes) when is_list(address_hashes) do
1127+
def matching_address_queries_list(query, direction, address_hashes, custom_sorting \\ [])
1128+
1129+
def matching_address_queries_list(query, :from, address_hashes, _custom_sorting) when is_list(address_hashes) do
11281130
[
11291131
from(
11301132
a in fragment("SELECT unnest(?) as from_address_hash", type(^address_hashes, {:array, Hash.Address})),
@@ -1140,7 +1142,7 @@ defmodule Explorer.Chain.Transaction do
11401142
]
11411143
end
11421144

1143-
def matching_address_queries_list(query, :to, address_hashes) when is_list(address_hashes) do
1145+
def matching_address_queries_list(query, :to, address_hashes, _custom_sorting) when is_list(address_hashes) do
11441146
[
11451147
from(
11461148
a in fragment("SELECT unnest(?) as to_address_hash", type(^address_hashes, {:array, Hash.Address})),
@@ -1173,30 +1175,51 @@ defmodule Explorer.Chain.Transaction do
11731175
]
11741176
end
11751177

1176-
def matching_address_queries_list(query, _direction, address_hashes) when is_list(address_hashes) do
1178+
def matching_address_queries_list(query, _direction, address_hashes, _custom_sorting) when is_list(address_hashes) do
11771179
matching_address_queries_list(query, :from, address_hashes) ++
11781180
matching_address_queries_list(query, :to, address_hashes)
11791181
end
11801182

1181-
def matching_address_queries_list(query, :from, address_hash) do
1182-
[where(query, [t], t.from_address_hash == ^address_hash)]
1183-
end
1183+
# in ^[address_hash] addresses this issue: https://github.com/blockscout/blockscout/issues/12393
1184+
def matching_address_queries_list(query, :from, address_hash, custom_sorting) do
1185+
order =
1186+
for {key, :block_number = value} <- custom_sorting do
1187+
{value, key}
1188+
end
1189+
|> Keyword.get(:block_number, :desc)
11841190

1185-
def matching_address_queries_list(query, :to, address_hash) do
11861191
[
1187-
where(query, [t], t.to_address_hash == ^address_hash),
1188-
where(query, [t], t.created_contract_address_hash == ^address_hash)
1192+
query
1193+
|> where([t], t.from_address_hash in ^[address_hash])
1194+
|> prepend_order_by([t], [{^order, t.from_address_hash}])
11891195
]
11901196
end
11911197

1192-
def matching_address_queries_list(query, _direction, address_hash) do
1198+
def matching_address_queries_list(query, :to, address_hash, custom_sorting) do
1199+
order =
1200+
for {key, :block_number = value} <- custom_sorting do
1201+
{value, key}
1202+
end
1203+
|> Keyword.get(:block_number, :desc)
1204+
11931205
[
1194-
where(query, [t], t.from_address_hash == ^address_hash),
1195-
where(query, [t], t.to_address_hash == ^address_hash),
1196-
where(query, [t], t.created_contract_address_hash == ^address_hash)
1206+
query
1207+
|> where([t], t.to_address_hash in ^[address_hash])
1208+
|> prepend_order_by([t], [{^order, t.to_address_hash}]),
1209+
query
1210+
|> where(
1211+
[t],
1212+
t.created_contract_address_hash in ^[address_hash]
1213+
)
1214+
|> prepend_order_by([t], [{^order, t.created_contract_address_hash}])
11971215
]
11981216
end
11991217

1218+
def matching_address_queries_list(query, _direction, address_hash, custom_sorting) do
1219+
matching_address_queries_list(query, :from, address_hash, custom_sorting) ++
1220+
matching_address_queries_list(query, :to, address_hash, custom_sorting)
1221+
end
1222+
12001223
def not_pending_transactions(query) do
12011224
where(query, [t], not is_nil(t.block_number))
12021225
end
@@ -1577,13 +1600,14 @@ defmodule Explorer.Chain.Transaction do
15771600
direction = Keyword.get(options, :direction)
15781601
necessity_by_association = Keyword.get(options, :necessity_by_association, %{})
15791602
old_ui? = old_ui? || is_tuple(Keyword.get(options, :paging_options, Chain.default_paging_options()).key)
1603+
sorting_options = Keyword.get(options, :sorting, [])
15801604

15811605
options
15821606
|> address_to_transactions_tasks_query(false, old_ui?)
15831607
|> not_dropped_or_replaced_transactions()
15841608
|> Chain.join_associations(necessity_by_association)
15851609
|> put_has_token_transfers_to_transaction(old_ui?)
1586-
|> matching_address_queries_list(direction, address_hash)
1610+
|> matching_address_queries_list(direction, address_hash, sorting_options)
15871611
|> Enum.map(fn query -> Task.async(fn -> Chain.select_repo(options).all(query) end) end)
15881612
end
15891613

@@ -1650,17 +1674,11 @@ defmodule Explorer.Chain.Transaction do
16501674
end
16511675
end
16521676

1653-
defp compare_custom_sorting([{block_order, :block_number}, {index_order, :index}]) do
1654-
fn a, b ->
1655-
case {Helper.compare(a.block_number, b.block_number), Helper.compare(a.index, b.index)} do
1656-
{:eq, :eq} -> compare_default_sorting(a, b)
1657-
{:eq, :gt} -> index_order == :desc
1658-
{:eq, :lt} -> index_order == :asc
1659-
{:gt, _} -> block_order == :desc
1660-
{:lt, _} -> block_order == :asc
1661-
end
1662-
end
1663-
end
1677+
defp compare_custom_sorting([{:desc, :block_number}, {:desc, :index}, {:desc, :inserted_at}, {:asc, :hash}]),
1678+
do: &compare_default_sorting/2
1679+
1680+
defp compare_custom_sorting([{:asc, :block_number}, {:asc, :index}, {:asc, :inserted_at}, {:desc, :hash}]),
1681+
do: &(!compare_default_sorting(&1, &2))
16641682

16651683
defp compare_custom_sorting([{:dynamic, :fee, order, _dynamic_fee}]) do
16661684
fn a, b ->

0 commit comments

Comments
 (0)