Split address transactions query into separate query/fetches and combine the results due to postgres not selecting optimized query plan consistently

pull/753/head
Stamates 6 years ago
parent a0ba0323ab
commit c515d765c1
  1. 19
      apps/explorer/lib/explorer/chain.ex
  2. 18
      apps/explorer/lib/explorer/chain/token_transfer.ex
  3. 85
      apps/explorer/lib/explorer/chain/transaction.ex

@ -182,14 +182,29 @@ defmodule Explorer.Chain do
when is_list(options) do
direction = Keyword.get(options, :direction)
necessity_by_association = Keyword.get(options, :necessity_by_association, %{})
paging_options = Keyword.get(options, :paging_options, @default_paging_options)
options
|> Keyword.get(:paging_options, @default_paging_options)
transaction_matches = paging_options
|> fetch_transactions()
|> Transaction.where_address_fields_match(address_hash, direction)
|> join_associations(necessity_by_association)
|> Transaction.preload_token_transfers(address_hash)
|> Repo.all()
token_transfer_matches = paging_options
|> fetch_transactions()
|> TokenTransfer.where_address_fields_match(address_hash, direction)
|> join_associations(necessity_by_association)
|> Transaction.preload_token_transfers(address_hash)
|> Repo.all()
transaction_matches
|> MapSet.new()
|> MapSet.union(MapSet.new(token_transfer_matches))
|> MapSet.to_list()
|> Enum.sort_by(& &1.block_number, &>=/2)
|> Enum.sort_by(& &1.index, &>=/2)
|> Enum.slice(0..paging_options.page_size)
end
@doc """

@ -148,4 +148,22 @@ defmodule Explorer.Chain.TokenTransfer do
token_transfer.inserted_at < ^inserted_at
)
end
def where_address_fields_match(query, address_hash, :from) do
query
|> join(:left, [transaction], tt in assoc(transaction, :token_transfers))
|> where([_transaction, tt], tt.from_address_hash == ^address_hash)
end
def where_address_fields_match(query, address_hash, :to) do
query
|> join(:left, [transaction], tt in assoc(transaction, :token_transfers))
|> where([_transaction, tt], tt.to_address_hash == ^address_hash)
end
def where_address_fields_match(query, address_hash, _) do
query
|> join(:left, [transaction], tt in assoc(transaction, :token_transfers))
|> where([_transaction, tt], tt.to_address_hash == ^address_hash or tt.from_address_hash == ^address_hash)
end
end

@ -3,7 +3,7 @@ defmodule Explorer.Chain.Transaction do
use Explorer.Schema
import Ecto.Query, only: [from: 2, join: 5, preload: 3]
import Ecto.Query, only: [from: 2, preload: 3, where: 3]
alias Ecto.Changeset
@ -424,90 +424,19 @@ defmodule Explorer.Chain.Transaction do
to token_contract_address_hash, to_address_hash or from_address_hash from Token Transfers's table.
"""
def where_address_fields_match(query, address_hash, :to) do
join(
query,
:inner,
[transaction],
matches in fragment(
"""
WITH hashes AS (
(
SELECT t0.hash AS hash
FROM transactions AS t0
WHERE t0.to_address_hash = ? OR t0.created_contract_address_hash = ?
)
UNION ALL
(
SELECT tt.transaction_hash AS hash
FROM token_transfers AS tt
WHERE tt.to_address_hash = ?
)
) SELECT * from hashes
""",
^address_hash.bytes,
^address_hash.bytes,
^address_hash.bytes
),
transaction.hash == matches.hash
)
where(query, [t], t.to_address_hash == ^address_hash or t.created_contract_address_hash == ^address_hash)
end
def where_address_fields_match(query, address_hash, :from) do
join(
query,
:inner,
[transaction],
matches in fragment(
"""
WITH hashes AS (
(
SELECT t0.hash AS hash
FROM transactions AS t0
WHERE t0.from_address_hash = ?
)
UNION ALL
(
SELECT tt.transaction_hash AS hash
FROM token_transfers AS tt
WHERE tt.from_address_hash = ?
)
) SELECT * from hashes
""",
^address_hash.bytes,
^address_hash.bytes
),
transaction.hash == matches.hash
)
where(query, [t], t.from_address_hash == ^address_hash or t.created_contract_address_hash == ^address_hash)
end
def where_address_fields_match(query, address_hash, nil) do
join(
where(
query,
:inner,
[transaction],
matches in fragment(
"""
WITH hashes AS (
(
SELECT t0.hash AS hash
FROM transactions AS t0
WHERE t0.to_address_hash = ? OR t0.from_address_hash = ? OR t0.created_contract_address_hash = ?
)
UNION ALL
(
SELECT tt.transaction_hash AS hash
FROM token_transfers AS tt
WHERE tt.to_address_hash = ? OR tt.from_address_hash = ?
)
) SELECT * from hashes
""",
^address_hash.bytes,
^address_hash.bytes,
^address_hash.bytes,
^address_hash.bytes,
^address_hash.bytes
),
transaction.hash == matches.hash
[t],
t.to_address_hash == ^address_hash or t.from_address_hash == ^address_hash or
t.created_contract_address_hash == ^address_hash
)
end

Loading…
Cancel
Save