Use table statistics estimate for total transaction

count to speed up page load.
pull/256/head
Stamates 7 years ago
parent fa455e331d
commit 7166ce4216
  1. 57
      apps/explorer/lib/explorer/chain.ex
  2. 2
      apps/explorer_web/lib/explorer_web/controllers/pending_transaction_controller.ex
  3. 2
      apps/explorer_web/lib/explorer_web/controllers/transaction_controller.ex
  4. 2
      apps/explorer_web/test/explorer_web/controllers/transaction_controller_test.exs

@ -6,6 +6,7 @@ defmodule Explorer.Chain do
import Ecto.Query,
only: [from: 2, join: 4, limit: 2, or_where: 3, order_by: 2, order_by: 3, preload: 2, where: 2, where: 3]
alias Ecto.Adapters.SQL
alias Ecto.{Changeset, Multi}
alias Explorer.Chain.{
@ -1495,41 +1496,30 @@ defmodule Explorer.Chain do
@doc """
Count of `t:Explorer.Chain.Transaction.t/0`.
With no options or an explicit `pending: nil`, both collated and pending transactions will be counted.
With :all both collated and pending transactions will be counted using estimates from table statistics.
iex> insert(:transaction)
iex> :transaction |> insert() |> with_block()
iex> Explorer.Chain.transaction_count()
2
iex> Explorer.Chain.transaction_count(pending: nil)
2
To count only collated transactions, pass `pending: false`.
iex> 2 |> insert_list(:transaction)
iex> 3 |> insert_list(:transaction) |> with_block()
iex> Explorer.Chain.transaction_count(pending: false)
3
iex> Explorer.Chain.transaction_count(:pending)
1
To count only pending transactions, pass `pending: true`.
## Arguments
iex> 2 |> insert_list(:transaction)
iex> 3 |> insert_list(:transaction) |> with_block()
iex> Explorer.Chain.transaction_count(pending: true)
2
* `:all` - returns an estimated count of all collated and pending transactions using table statistics
* `:pending` - returns a count of all pending transactions
## Options
"""
@spec transaction_count(:all | :pending) :: non_neg_integer()
def transaction_count(:all) do
%Postgrex.Result{rows: [[rows]]} =
SQL.query!(Repo, "SELECT reltuples::BIGINT AS estimate FROM pg_class WHERE relname='transactions'")
* `:pending`
* `nil` - count all transactions
* `true` - only count pending transactions
* `false` - only count collated transactions
rows
end
"""
@spec transaction_count([{:pending, boolean()}]) :: non_neg_integer()
def transaction_count(options \\ []) when is_list(options) do
def transaction_count(:pending) do
Transaction
|> where_pending(options)
|> where([transaction], is_nil(transaction.block_hash))
|> Repo.aggregate(:count, :hash)
end
@ -2043,21 +2033,6 @@ defmodule Explorer.Chain do
end)
end
defp where_pending(query, options) when is_list(options) do
pending = Keyword.get(options, :pending)
case pending do
false ->
from(transaction in query, where: not is_nil(transaction.block_hash))
true ->
from(transaction in query, where: is_nil(transaction.block_hash))
nil ->
query
end
end
defp where_transaction_has_multiple_internal_transactions(query) do
where(
query,

@ -16,7 +16,7 @@ defmodule ExplorerWeb.PendingTransactionController do
full_options = Keyword.merge([necessity_by_association: %{from_address: :optional, to_address: :optional}], options)
transactions = Chain.recent_pending_transactions(full_options)
last_seen_pending_inserted_at = last_seen_pending_inserted_at(transactions.entries)
transaction_count = Chain.transaction_count(pending: true)
transaction_count = Chain.transaction_count(:pending)
render(
conn,

@ -36,7 +36,7 @@ defmodule ExplorerWeb.TransactionController do
)
transactions = Chain.recent_collated_transactions(full_options)
transaction_count = Chain.transaction_count()
transaction_count = Chain.transaction_count(:all)
render(
conn,

@ -23,7 +23,7 @@ defmodule ExplorerWeb.TransactionControllerTest do
conn = get(conn, "/en/transactions")
assert conn.assigns.transaction_count == 1
assert is_integer(conn.assigns.transaction_count)
end
test "excludes pending transactions", %{conn: conn} do

Loading…
Cancel
Save