From d59a92fd9b58e58c2cc4681bce0eaed127c6a26d Mon Sep 17 00:00:00 2001 From: Thomas Droxler Date: Thu, 18 Jun 2026 16:38:37 +0200 Subject: [PATCH 1/2] Drop unused database indexes --- .../explorer/persistence/DBInitializer.scala | 3 -- .../explorer/persistence/Migrations.scala | 40 ++++++++++++++++++- .../persistence/queries/BlockQueries.scala | 5 ++- .../persistence/queries/OutputQueries.scala | 11 ++--- .../schema/BlockHeaderSchema.scala | 2 +- .../persistence/schema/ContractSchema.scala | 7 +--- .../schema/MempoolTransactionSchema.scala | 4 +- .../persistence/schema/TokenInfoSchema.scala | 1 - .../schema/TokenOutputSchema.scala | 12 +++--- .../schema/TokenTxPerAddressSchema.scala | 17 +------- .../schema/TransactionHistorySchema.scala | 3 +- .../schema/TransactionPerAddressSchema.scala | 2 - .../schema/TransactionPerTokenSchema.scala | 1 - .../schema/TransactionSchema.scala | 2 - .../explorer/service/IndexChecker.scala | 3 +- 15 files changed, 57 insertions(+), 56 deletions(-) diff --git a/app/src/main/scala/org/alephium/explorer/persistence/DBInitializer.scala b/app/src/main/scala/org/alephium/explorer/persistence/DBInitializer.scala index f9c0ccc83..f0c2524ac 100644 --- a/app/src/main/scala/org/alephium/explorer/persistence/DBInitializer.scala +++ b/app/src/main/scala/org/alephium/explorer/persistence/DBInitializer.scala @@ -102,9 +102,6 @@ object DBInitializer extends StrictLogging { logger.info("Create Indexes") run(for { _ <- BlockHeaderSchema.createBlockHeadersIndexes() - _ <- TransactionSchema.createMainChainIndex() - _ <- InputSchema.createMainChainIndex() - _ <- OutputSchema.createMainChainIndex() _ <- TransactionPerAddressSchema.createIndexes() _ <- OutputSchema.createNonSpentIndex() _ <- InputSchema.createOutputRefAddressNullIndex() diff --git a/app/src/main/scala/org/alephium/explorer/persistence/Migrations.scala b/app/src/main/scala/org/alephium/explorer/persistence/Migrations.scala index ad29e502d..c6dc50c43 100644 --- a/app/src/main/scala/org/alephium/explorer/persistence/Migrations.scala +++ b/app/src/main/scala/org/alephium/explorer/persistence/Migrations.scala @@ -29,7 +29,7 @@ import org.alephium.util.discard object Migrations extends StrictLogging { // scalastyle:off magic.number - val latestVersion: MigrationVersion = MigrationVersion(11) + val latestVersion: MigrationVersion = MigrationVersion(12) def migration1(implicit ec: ExecutionContext): DBActionAll[Unit] = { // We retrigger the download of fungible and non-fungible tokens' metadata that have sub-category @@ -222,6 +222,41 @@ object Migrations extends StrictLogging { """.map(_ => ()) } + private val unusedIndexes: ArraySeq[String] = + ArraySeq( + "utransactions_last_seen_idx", + "token_info_category_idx", + "contracts_std_interface_id_guessed_idx", + "contracts_category_idx", + "transactions_history_interval_type_idx", + "token_tx_per_address_token_idx", + "token_outputs_token_idx", + "token_outputs_spent_timestamp_idx", + "token_tx_per_addresses_timestamp_idx", + "transaction_per_token_hash_idx", + "token_tx_per_addresses_block_timestamp_tx_order_idx", + "token_tx_per_address_hash_idx", + "token_tx_per_address_groupless_idx", + "inputs_main_chain_idx", + "block_headers_main_chain_idx", + "outputs_main_chain_idx", + "transaction_per_addresses_main_chain_idx", + "transactions_main_chain_idx", + "txs_chain_to_idx", + "txs_chain_from_idx", + "txs_per_address_tx_hash_idx" + ) + + private def dropUnusedIndex(indexName: String)(implicit + ec: ExecutionContext + ): DBActionAll[Unit] = + sqlu"DROP INDEX IF EXISTS public.#$indexName".map(_ => ()) + + def migration12(implicit ec: ExecutionContext): DBActionAll[Unit] = + DBIOAction + .sequence(unusedIndexes.map(indexName => dropUnusedIndex(indexName))) + .map(_ => ()) + private def migrations(implicit explorerConfig: ExplorerConfig, ec: ExecutionContext @@ -236,7 +271,8 @@ object Migrations extends StrictLogging { migration8, migration9, migration10, - migration11 + migration11, + migration12 ) def backgroundCoinbaseMigration()(implicit diff --git a/app/src/main/scala/org/alephium/explorer/persistence/queries/BlockQueries.scala b/app/src/main/scala/org/alephium/explorer/persistence/queries/BlockQueries.scala index b49991bdb..900d01eae 100644 --- a/app/src/main/scala/org/alephium/explorer/persistence/queries/BlockQueries.scala +++ b/app/src/main/scala/org/alephium/explorer/persistence/queries/BlockQueries.scala @@ -68,12 +68,13 @@ object BlockQueries extends StrictLogging { def explainMainChainQuery()(implicit ec: ExecutionContext): DBActionR[ExplainResult] = mainChainQuery.result.explainAnalyze() map { explain => + val fullIndexUsed = explain.mkString contains "block_headers_full_index" ExplainResult( queryName = "mainChainQuery", queryInput = "Unit", explain = explain, - messages = Iterable.empty, - passed = explain.mkString contains "block_headers_main_chain_idx" + messages = Iterable(s"Used block_headers_full_index = $fullIndexUsed"), + passed = fullIndexUsed ) } diff --git a/app/src/main/scala/org/alephium/explorer/persistence/queries/OutputQueries.scala b/app/src/main/scala/org/alephium/explorer/persistence/queries/OutputQueries.scala index bb1b375b4..97b24563f 100644 --- a/app/src/main/scala/org/alephium/explorer/persistence/queries/OutputQueries.scala +++ b/app/src/main/scala/org/alephium/explorer/persistence/queries/OutputQueries.scala @@ -399,14 +399,11 @@ object OutputQueries { key match { case Some(key) => getTxnHashBuilder(key).explainAnalyze() map { explain => - val explainString = explain.mkString - val outputs_pk_used = explainString contains "outputs_pk" - val outputs_main_chain_idx_used = explainString contains "outputs_main_chain_idx" - val passed = outputs_pk_used && outputs_main_chain_idx_used + val explainString = explain.mkString + val outputs_pk_used = explainString contains "outputs_pk" val message = ArraySeq( - s"Used outputs_main_chain_idx = $outputs_main_chain_idx_used", - s"Used outputs_pk = $outputs_pk_used" + s"Used outputs_pk = $outputs_pk_used" ) ExplainResult( @@ -414,7 +411,7 @@ object OutputQueries { queryInput = key.toString(), explain = explain, messages = message, - passed = passed + passed = outputs_pk_used ) } diff --git a/app/src/main/scala/org/alephium/explorer/persistence/schema/BlockHeaderSchema.scala b/app/src/main/scala/org/alephium/explorer/persistence/schema/BlockHeaderSchema.scala index 4df1a67b1..aa0e62ef4 100644 --- a/app/src/main/scala/org/alephium/explorer/persistence/schema/BlockHeaderSchema.scala +++ b/app/src/main/scala/org/alephium/explorer/persistence/schema/BlockHeaderSchema.scala @@ -88,7 +88,7 @@ object BlockHeaderSchema extends SchemaMainChain[BlockHeader]("block_headers") { /** Joins all indexes created via raw SQL */ def createBlockHeadersIndexes(): DBIO[Unit] = - DBIO.seq(fullIndex(), createMainChainIndex()) + DBIO.seq(fullIndex()) val table: TableQuery[BlockHeaders] = TableQuery[BlockHeaders] } diff --git a/app/src/main/scala/org/alephium/explorer/persistence/schema/ContractSchema.scala b/app/src/main/scala/org/alephium/explorer/persistence/schema/ContractSchema.scala index f93e77619..5968bc44d 100644 --- a/app/src/main/scala/org/alephium/explorer/persistence/schema/ContractSchema.scala +++ b/app/src/main/scala/org/alephium/explorer/persistence/schema/ContractSchema.scala @@ -56,11 +56,8 @@ object ContractSchema extends SchemaMainChain[ContractEntity]("contracts") { def pk: PrimaryKey = primaryKey("contracts_pk", (contract, creationBlockHash)) - def contractIdx: Index = index("contracts_contract_idx", contract) - def parentIdx: Index = index("contracts_parent_idx", parent) - def stdInterfaceIdGuessedIdx: Index = - index("contracts_std_interface_id_guessed_idx", stdInterfaceIdGuessed) - def categoryIdx: Index = index("contracts_category_idx", category) + def contractIdx: Index = index("contracts_contract_idx", contract) + def parentIdx: Index = index("contracts_parent_idx", parent) def interfaceIdIdx: Index = index("contracts_interface_id_idx", interfaceId) } diff --git a/app/src/main/scala/org/alephium/explorer/persistence/schema/MempoolTransactionSchema.scala b/app/src/main/scala/org/alephium/explorer/persistence/schema/MempoolTransactionSchema.scala index fb0a0b982..a2abb44bd 100644 --- a/app/src/main/scala/org/alephium/explorer/persistence/schema/MempoolTransactionSchema.scala +++ b/app/src/main/scala/org/alephium/explorer/persistence/schema/MempoolTransactionSchema.scala @@ -4,7 +4,7 @@ package org.alephium.explorer.persistence.schema import slick.jdbc.PostgresProfile.api._ -import slick.lifted.{Index, ProvenShape} +import slick.lifted.ProvenShape import org.alephium.explorer.persistence.model.MempoolTransactionEntity import org.alephium.explorer.persistence.schema.CustomJdbcTypes._ @@ -23,8 +23,6 @@ object MempoolTransactionSchema extends Schema[MempoolTransactionEntity]("utrans column[U256]("gas_price", O.SqlType("DECIMAL(80,0)")) // U256.MaxValue has 78 digits def lastSeen: Rep[TimeStamp] = column[TimeStamp]("last_seen") - def lastSeenIdx: Index = index("utransactions_last_seen_idx", lastSeen) - def * : ProvenShape[MempoolTransactionEntity] = (hash, chainFrom, chainTo, gasAmount, gasPrice, lastSeen) .<>((MempoolTransactionEntity.apply _).tupled, MempoolTransactionEntity.unapply) diff --git a/app/src/main/scala/org/alephium/explorer/persistence/schema/TokenInfoSchema.scala b/app/src/main/scala/org/alephium/explorer/persistence/schema/TokenInfoSchema.scala index 9451f93b5..81897cb18 100644 --- a/app/src/main/scala/org/alephium/explorer/persistence/schema/TokenInfoSchema.scala +++ b/app/src/main/scala/org/alephium/explorer/persistence/schema/TokenInfoSchema.scala @@ -24,7 +24,6 @@ object TokenInfoSchema extends SchemaMainChain[TokenInfoEntity]("token_info") { (token, lastUsed, category, interfaceId) .<>((TokenInfoEntity.apply _).tupled, TokenInfoEntity.unapply) - def categoryIdx: Index = index("token_info_category_idx", category) def interfaceIdIdx: Index = index("token_info_interface_id_idx", interfaceId) } diff --git a/app/src/main/scala/org/alephium/explorer/persistence/schema/TokenOutputSchema.scala b/app/src/main/scala/org/alephium/explorer/persistence/schema/TokenOutputSchema.scala index 5a56a3502..769d18bfb 100644 --- a/app/src/main/scala/org/alephium/explorer/persistence/schema/TokenOutputSchema.scala +++ b/app/src/main/scala/org/alephium/explorer/persistence/schema/TokenOutputSchema.scala @@ -43,13 +43,11 @@ object TokenOutputSchema extends SchemaMainChain[TokenOutputEntity]("token_outpu def pk: PrimaryKey = primaryKey("token_outputs_pk", (key, token, blockHash)) - def keyIdx: Index = index("token_outputs_key_idx", key) - def blockHashIdx: Index = index("token_outputs_block_hash_idx", blockHash) - def txHashIdx: Index = index("token_outputs_tx_hash_idx", txHash) - def addressIdx: Index = index("token_outputs_address_idx", address) - def timestampIdx: Index = index("token_outputs_timestamp_idx", timestamp) - def tokenIdx: Index = index("token_outputs_token_idx", token) - def spentTimestampIdx: Index = index("token_outputs_spent_timestamp_idx", spentTimestamp) + def keyIdx: Index = index("token_outputs_key_idx", key) + def blockHashIdx: Index = index("token_outputs_block_hash_idx", blockHash) + def txHashIdx: Index = index("token_outputs_tx_hash_idx", txHash) + def addressIdx: Index = index("token_outputs_address_idx", address) + def timestampIdx: Index = index("token_outputs_timestamp_idx", timestamp) def * : ProvenShape[TokenOutputEntity] = ( diff --git a/app/src/main/scala/org/alephium/explorer/persistence/schema/TokenTxPerAddressSchema.scala b/app/src/main/scala/org/alephium/explorer/persistence/schema/TokenTxPerAddressSchema.scala index 84c734784..327f76aa0 100644 --- a/app/src/main/scala/org/alephium/explorer/persistence/schema/TokenTxPerAddressSchema.scala +++ b/app/src/main/scala/org/alephium/explorer/persistence/schema/TokenTxPerAddressSchema.scala @@ -31,10 +31,8 @@ object TokenPerAddressSchema def pk: PrimaryKey = primaryKey("token_tx_per_address_pk", (txHash, blockHash, address, token)) - def hashIdx: Index = index("token_tx_per_address_hash_idx", txHash) def blockHashIdx: Index = index("token_tx_per_address_block_hash_idx", blockHash) def addressIdx: Index = index("token_tx_per_address_address_idx", address) - def tokenIdx: Index = index("token_tx_per_address_token_idx", token) def tokenAddressIdx: Index = index("token_tx_per_address_token_address_idx", (token, address)) def * : ProvenShape[TokenTxPerAddressEntity] = @@ -53,15 +51,11 @@ object TokenPerAddressSchema } def createIndexes(): DBIO[Unit] = - DBIO.seq( - CommonIndex.blockTimestampTxOrderIndex(this), - CommonIndex.timestampIndex(this) - ) + DBIO.seq() def createConcurrentIndexes()(implicit ec: ExecutionContext): DBActionW[Unit] = for { _ <- createTokenGrouplessAddressIndex() - _ <- createGrouplessIndex() } yield () def createTokenGrouplessAddressIndex(): DBActionW[Int] = @@ -71,14 +65,5 @@ object TokenPerAddressSchema WHERE groupless_address IS NOT NULL; """ - def createGrouplessIndex(): DBActionW[Int] = - sqlu""" - CREATE INDEX CONCURRENTLY IF NOT EXISTS token_tx_per_address_groupless_idx - ON token_tx_per_addresses ( - token, address, groupless_address, block_timestamp, tx_order, tx_hash, block_hash - ) - WHERE groupless_address is not null AND main_chain = true; - """ - val table: TableQuery[TokenPerAddresses] = TableQuery[TokenPerAddresses] } diff --git a/app/src/main/scala/org/alephium/explorer/persistence/schema/TransactionHistorySchema.scala b/app/src/main/scala/org/alephium/explorer/persistence/schema/TransactionHistorySchema.scala index 9bc341580..c71662ef7 100644 --- a/app/src/main/scala/org/alephium/explorer/persistence/schema/TransactionHistorySchema.scala +++ b/app/src/main/scala/org/alephium/explorer/persistence/schema/TransactionHistorySchema.scala @@ -23,8 +23,7 @@ object TransactionHistorySchema extends Schema[TransactionHistoryEntity]("transa def pk: PrimaryKey = primaryKey("transactions_history_pk", (intervalType, timestamp, chainFrom, chainTo)) - def intervalTypeIdx: Index = index("transactions_history_interval_type_idx", intervalType) - def timestampIdx: Index = index("transactions_history_timestamp_idx", timestamp) + def timestampIdx: Index = index("transactions_history_timestamp_idx", timestamp) def * : ProvenShape[TransactionHistoryEntity] = (timestamp, chainFrom, chainTo, count, intervalType) diff --git a/app/src/main/scala/org/alephium/explorer/persistence/schema/TransactionPerAddressSchema.scala b/app/src/main/scala/org/alephium/explorer/persistence/schema/TransactionPerAddressSchema.scala index 3b0c9c403..a51416a1b 100644 --- a/app/src/main/scala/org/alephium/explorer/persistence/schema/TransactionPerAddressSchema.scala +++ b/app/src/main/scala/org/alephium/explorer/persistence/schema/TransactionPerAddressSchema.scala @@ -31,7 +31,6 @@ object TransactionPerAddressSchema def pk: PrimaryKey = primaryKey("txs_per_address_pk", (txHash, blockHash, address)) - def hashIdx: Index = index("txs_per_address_tx_hash_idx", txHash) def blockHashIdx: Index = index("txs_per_address_block_hash_idx", blockHash) def addressIdx: Index = index("txs_per_address_address_idx", address) def addressTimestampIdx: Index = @@ -54,7 +53,6 @@ object TransactionPerAddressSchema def createIndexes(): DBIO[Unit] = DBIO.seq( - createMainChainIndex(), CommonIndex.blockTimestampTxOrderIndex(this), CommonIndex.timestampIndex(this) ) diff --git a/app/src/main/scala/org/alephium/explorer/persistence/schema/TransactionPerTokenSchema.scala b/app/src/main/scala/org/alephium/explorer/persistence/schema/TransactionPerTokenSchema.scala index 36ed998df..68f8e4080 100644 --- a/app/src/main/scala/org/alephium/explorer/persistence/schema/TransactionPerTokenSchema.scala +++ b/app/src/main/scala/org/alephium/explorer/persistence/schema/TransactionPerTokenSchema.scala @@ -25,7 +25,6 @@ object TransactionPerTokenSchema def pk: PrimaryKey = primaryKey("transaction_per_token_pk", (hash, blockHash, token)) - def hashIdx: Index = index("transaction_per_token_hash_idx", hash) def blockHashIdx: Index = index("transaction_per_token_block_hash_idx", blockHash) def tokenIdx: Index = index("transaction_per_token_token_idx", token) diff --git a/app/src/main/scala/org/alephium/explorer/persistence/schema/TransactionSchema.scala b/app/src/main/scala/org/alephium/explorer/persistence/schema/TransactionSchema.scala index 38e7f0b56..5e1ef7089 100644 --- a/app/src/main/scala/org/alephium/explorer/persistence/schema/TransactionSchema.scala +++ b/app/src/main/scala/org/alephium/explorer/persistence/schema/TransactionSchema.scala @@ -44,8 +44,6 @@ object TransactionSchema extends SchemaMainChain[TransactionEntity]("transaction def timestampIdx: Index = index("txs_timestamp_idx", timestamp) def blockHashIdx: Index = index("txs_block_hash_idx", blockHash) - def chainFromIdx: Index = index("txs_chain_from_idx", chainFrom) - def chainToIdx: Index = index("txs_chain_to_idx", chainTo) def * : ProvenShape[TransactionEntity] = ( diff --git a/app/src/main/scala/org/alephium/explorer/service/IndexChecker.scala b/app/src/main/scala/org/alephium/explorer/service/IndexChecker.scala index 23c33034f..2a441ad17 100644 --- a/app/src/main/scala/org/alephium/explorer/service/IndexChecker.scala +++ b/app/src/main/scala/org/alephium/explorer/service/IndexChecker.scala @@ -33,7 +33,6 @@ object IndexChecker { b <- BlockQueries.explainListMainChainHeadersWithTxnNumber( Pagination.Reversible.unsafe(10000, 20) ) // far page - c <- BlockQueries.explainMainChainQuery() oldestOutputEntity <- OutputQueries.getMainChainOutputs(true).headOrEmpty latestOutputEntity <- OutputQueries.getMainChainOutputs(false).headOrEmpty d <- OutputQueries.explainGetTxnHash(oldestOutputEntity.map(_.key).headOption) @@ -42,6 +41,6 @@ object IndexChecker { latestInputEntity <- InputQueries.getMainChainInputs(false).headOrEmpty f <- InputQueries.explainInputsFromTxs(oldestInputEntity.map(_.hashes())) g <- InputQueries.explainInputsFromTxs(latestInputEntity.map(_.hashes())) - } yield ArraySeq(a, b, c, d, e, f, g).sortBy(_.passed) + } yield ArraySeq(a, b, d, e, f, g).sortBy(_.passed) } From de0b78b79e8259bc622fbae0d34fb13bdfc216ba Mon Sep 17 00:00:00 2001 From: Thomas Droxler Date: Thu, 18 Jun 2026 16:47:58 +0200 Subject: [PATCH 2/2] Restore dropped database indexes --- .../explorer/persistence/Migrations.scala | 81 ++++++++++++++++++- .../persistence/queries/BlockQueries.scala | 5 +- .../persistence/queries/OutputQueries.scala | 11 ++- .../schema/BlockHeaderSchema.scala | 2 +- .../persistence/schema/ContractSchema.scala | 7 +- .../schema/MempoolTransactionSchema.scala | 4 +- .../persistence/schema/TokenInfoSchema.scala | 1 + .../schema/TokenOutputSchema.scala | 12 +-- .../schema/TokenTxPerAddressSchema.scala | 17 +++- .../schema/TransactionHistorySchema.scala | 3 +- .../schema/TransactionPerAddressSchema.scala | 2 + .../schema/TransactionPerTokenSchema.scala | 1 + .../schema/TransactionSchema.scala | 2 + .../explorer/service/IndexChecker.scala | 3 +- 14 files changed, 130 insertions(+), 21 deletions(-) diff --git a/app/src/main/scala/org/alephium/explorer/persistence/Migrations.scala b/app/src/main/scala/org/alephium/explorer/persistence/Migrations.scala index c6dc50c43..261917dc2 100644 --- a/app/src/main/scala/org/alephium/explorer/persistence/Migrations.scala +++ b/app/src/main/scala/org/alephium/explorer/persistence/Migrations.scala @@ -29,7 +29,7 @@ import org.alephium.util.discard object Migrations extends StrictLogging { // scalastyle:off magic.number - val latestVersion: MigrationVersion = MigrationVersion(12) + val latestVersion: MigrationVersion = MigrationVersion(13) def migration1(implicit ec: ExecutionContext): DBActionAll[Unit] = { // We retrigger the download of fungible and non-fungible tokens' metadata that have sub-category @@ -257,6 +257,82 @@ object Migrations extends StrictLogging { .sequence(unusedIndexes.map(indexName => dropUnusedIndex(indexName))) .map(_ => ()) + // scalastyle:off method.length + def migration13(implicit ec: ExecutionContext): DBActionAll[Unit] = + sqlu""" + CREATE INDEX IF NOT EXISTS utransactions_last_seen_idx + ON utransactions (last_seen); + + CREATE INDEX IF NOT EXISTS token_info_category_idx + ON token_info (category); + + CREATE INDEX IF NOT EXISTS contracts_std_interface_id_guessed_idx + ON contracts (std_interface_id_guessed); + + CREATE INDEX IF NOT EXISTS contracts_category_idx + ON contracts (category); + + CREATE INDEX IF NOT EXISTS transactions_history_interval_type_idx + ON transactions_history (interval_type); + + CREATE INDEX IF NOT EXISTS token_tx_per_address_token_idx + ON token_tx_per_addresses (token); + + CREATE INDEX IF NOT EXISTS token_outputs_token_idx + ON token_outputs (token); + + CREATE INDEX IF NOT EXISTS token_outputs_spent_timestamp_idx + ON token_outputs (spent_timestamp); + + CREATE INDEX IF NOT EXISTS token_tx_per_addresses_timestamp_idx + ON token_tx_per_addresses (block_timestamp DESC); + + CREATE INDEX IF NOT EXISTS transaction_per_token_hash_idx + ON transaction_per_token (tx_hash); + + CREATE INDEX IF NOT EXISTS token_tx_per_addresses_block_timestamp_tx_order_idx + ON token_tx_per_addresses (block_timestamp DESC, tx_order ASC); + + CREATE INDEX IF NOT EXISTS token_tx_per_address_hash_idx + ON token_tx_per_addresses (tx_hash); + + CREATE INDEX IF NOT EXISTS token_tx_per_address_groupless_idx + ON token_tx_per_addresses ( + token, address, groupless_address, block_timestamp, tx_order, tx_hash, block_hash + ) + WHERE groupless_address IS NOT NULL AND main_chain = true; + + CREATE INDEX IF NOT EXISTS inputs_main_chain_idx + ON inputs (main_chain) + WHERE main_chain = true; + + CREATE INDEX IF NOT EXISTS block_headers_main_chain_idx + ON block_headers (main_chain) + WHERE main_chain = true; + + CREATE INDEX IF NOT EXISTS outputs_main_chain_idx + ON outputs (main_chain) + WHERE main_chain = true; + + CREATE INDEX IF NOT EXISTS transaction_per_addresses_main_chain_idx + ON transaction_per_addresses (main_chain) + WHERE main_chain = true; + + CREATE INDEX IF NOT EXISTS transactions_main_chain_idx + ON transactions (main_chain) + WHERE main_chain = true; + + CREATE INDEX IF NOT EXISTS txs_chain_to_idx + ON transactions (chain_to); + + CREATE INDEX IF NOT EXISTS txs_chain_from_idx + ON transactions (chain_from); + + CREATE INDEX IF NOT EXISTS txs_per_address_tx_hash_idx + ON transaction_per_addresses (tx_hash); + """.map(_ => ()) + // scalastyle:on method.length + private def migrations(implicit explorerConfig: ExplorerConfig, ec: ExecutionContext @@ -272,7 +348,8 @@ object Migrations extends StrictLogging { migration9, migration10, migration11, - migration12 + migration12, + migration13 ) def backgroundCoinbaseMigration()(implicit diff --git a/app/src/main/scala/org/alephium/explorer/persistence/queries/BlockQueries.scala b/app/src/main/scala/org/alephium/explorer/persistence/queries/BlockQueries.scala index 900d01eae..b49991bdb 100644 --- a/app/src/main/scala/org/alephium/explorer/persistence/queries/BlockQueries.scala +++ b/app/src/main/scala/org/alephium/explorer/persistence/queries/BlockQueries.scala @@ -68,13 +68,12 @@ object BlockQueries extends StrictLogging { def explainMainChainQuery()(implicit ec: ExecutionContext): DBActionR[ExplainResult] = mainChainQuery.result.explainAnalyze() map { explain => - val fullIndexUsed = explain.mkString contains "block_headers_full_index" ExplainResult( queryName = "mainChainQuery", queryInput = "Unit", explain = explain, - messages = Iterable(s"Used block_headers_full_index = $fullIndexUsed"), - passed = fullIndexUsed + messages = Iterable.empty, + passed = explain.mkString contains "block_headers_main_chain_idx" ) } diff --git a/app/src/main/scala/org/alephium/explorer/persistence/queries/OutputQueries.scala b/app/src/main/scala/org/alephium/explorer/persistence/queries/OutputQueries.scala index 97b24563f..bb1b375b4 100644 --- a/app/src/main/scala/org/alephium/explorer/persistence/queries/OutputQueries.scala +++ b/app/src/main/scala/org/alephium/explorer/persistence/queries/OutputQueries.scala @@ -399,11 +399,14 @@ object OutputQueries { key match { case Some(key) => getTxnHashBuilder(key).explainAnalyze() map { explain => - val explainString = explain.mkString - val outputs_pk_used = explainString contains "outputs_pk" + val explainString = explain.mkString + val outputs_pk_used = explainString contains "outputs_pk" + val outputs_main_chain_idx_used = explainString contains "outputs_main_chain_idx" + val passed = outputs_pk_used && outputs_main_chain_idx_used val message = ArraySeq( - s"Used outputs_pk = $outputs_pk_used" + s"Used outputs_main_chain_idx = $outputs_main_chain_idx_used", + s"Used outputs_pk = $outputs_pk_used" ) ExplainResult( @@ -411,7 +414,7 @@ object OutputQueries { queryInput = key.toString(), explain = explain, messages = message, - passed = outputs_pk_used + passed = passed ) } diff --git a/app/src/main/scala/org/alephium/explorer/persistence/schema/BlockHeaderSchema.scala b/app/src/main/scala/org/alephium/explorer/persistence/schema/BlockHeaderSchema.scala index aa0e62ef4..4df1a67b1 100644 --- a/app/src/main/scala/org/alephium/explorer/persistence/schema/BlockHeaderSchema.scala +++ b/app/src/main/scala/org/alephium/explorer/persistence/schema/BlockHeaderSchema.scala @@ -88,7 +88,7 @@ object BlockHeaderSchema extends SchemaMainChain[BlockHeader]("block_headers") { /** Joins all indexes created via raw SQL */ def createBlockHeadersIndexes(): DBIO[Unit] = - DBIO.seq(fullIndex()) + DBIO.seq(fullIndex(), createMainChainIndex()) val table: TableQuery[BlockHeaders] = TableQuery[BlockHeaders] } diff --git a/app/src/main/scala/org/alephium/explorer/persistence/schema/ContractSchema.scala b/app/src/main/scala/org/alephium/explorer/persistence/schema/ContractSchema.scala index 5968bc44d..f93e77619 100644 --- a/app/src/main/scala/org/alephium/explorer/persistence/schema/ContractSchema.scala +++ b/app/src/main/scala/org/alephium/explorer/persistence/schema/ContractSchema.scala @@ -56,8 +56,11 @@ object ContractSchema extends SchemaMainChain[ContractEntity]("contracts") { def pk: PrimaryKey = primaryKey("contracts_pk", (contract, creationBlockHash)) - def contractIdx: Index = index("contracts_contract_idx", contract) - def parentIdx: Index = index("contracts_parent_idx", parent) + def contractIdx: Index = index("contracts_contract_idx", contract) + def parentIdx: Index = index("contracts_parent_idx", parent) + def stdInterfaceIdGuessedIdx: Index = + index("contracts_std_interface_id_guessed_idx", stdInterfaceIdGuessed) + def categoryIdx: Index = index("contracts_category_idx", category) def interfaceIdIdx: Index = index("contracts_interface_id_idx", interfaceId) } diff --git a/app/src/main/scala/org/alephium/explorer/persistence/schema/MempoolTransactionSchema.scala b/app/src/main/scala/org/alephium/explorer/persistence/schema/MempoolTransactionSchema.scala index a2abb44bd..fb0a0b982 100644 --- a/app/src/main/scala/org/alephium/explorer/persistence/schema/MempoolTransactionSchema.scala +++ b/app/src/main/scala/org/alephium/explorer/persistence/schema/MempoolTransactionSchema.scala @@ -4,7 +4,7 @@ package org.alephium.explorer.persistence.schema import slick.jdbc.PostgresProfile.api._ -import slick.lifted.ProvenShape +import slick.lifted.{Index, ProvenShape} import org.alephium.explorer.persistence.model.MempoolTransactionEntity import org.alephium.explorer.persistence.schema.CustomJdbcTypes._ @@ -23,6 +23,8 @@ object MempoolTransactionSchema extends Schema[MempoolTransactionEntity]("utrans column[U256]("gas_price", O.SqlType("DECIMAL(80,0)")) // U256.MaxValue has 78 digits def lastSeen: Rep[TimeStamp] = column[TimeStamp]("last_seen") + def lastSeenIdx: Index = index("utransactions_last_seen_idx", lastSeen) + def * : ProvenShape[MempoolTransactionEntity] = (hash, chainFrom, chainTo, gasAmount, gasPrice, lastSeen) .<>((MempoolTransactionEntity.apply _).tupled, MempoolTransactionEntity.unapply) diff --git a/app/src/main/scala/org/alephium/explorer/persistence/schema/TokenInfoSchema.scala b/app/src/main/scala/org/alephium/explorer/persistence/schema/TokenInfoSchema.scala index 81897cb18..9451f93b5 100644 --- a/app/src/main/scala/org/alephium/explorer/persistence/schema/TokenInfoSchema.scala +++ b/app/src/main/scala/org/alephium/explorer/persistence/schema/TokenInfoSchema.scala @@ -24,6 +24,7 @@ object TokenInfoSchema extends SchemaMainChain[TokenInfoEntity]("token_info") { (token, lastUsed, category, interfaceId) .<>((TokenInfoEntity.apply _).tupled, TokenInfoEntity.unapply) + def categoryIdx: Index = index("token_info_category_idx", category) def interfaceIdIdx: Index = index("token_info_interface_id_idx", interfaceId) } diff --git a/app/src/main/scala/org/alephium/explorer/persistence/schema/TokenOutputSchema.scala b/app/src/main/scala/org/alephium/explorer/persistence/schema/TokenOutputSchema.scala index 769d18bfb..5a56a3502 100644 --- a/app/src/main/scala/org/alephium/explorer/persistence/schema/TokenOutputSchema.scala +++ b/app/src/main/scala/org/alephium/explorer/persistence/schema/TokenOutputSchema.scala @@ -43,11 +43,13 @@ object TokenOutputSchema extends SchemaMainChain[TokenOutputEntity]("token_outpu def pk: PrimaryKey = primaryKey("token_outputs_pk", (key, token, blockHash)) - def keyIdx: Index = index("token_outputs_key_idx", key) - def blockHashIdx: Index = index("token_outputs_block_hash_idx", blockHash) - def txHashIdx: Index = index("token_outputs_tx_hash_idx", txHash) - def addressIdx: Index = index("token_outputs_address_idx", address) - def timestampIdx: Index = index("token_outputs_timestamp_idx", timestamp) + def keyIdx: Index = index("token_outputs_key_idx", key) + def blockHashIdx: Index = index("token_outputs_block_hash_idx", blockHash) + def txHashIdx: Index = index("token_outputs_tx_hash_idx", txHash) + def addressIdx: Index = index("token_outputs_address_idx", address) + def timestampIdx: Index = index("token_outputs_timestamp_idx", timestamp) + def tokenIdx: Index = index("token_outputs_token_idx", token) + def spentTimestampIdx: Index = index("token_outputs_spent_timestamp_idx", spentTimestamp) def * : ProvenShape[TokenOutputEntity] = ( diff --git a/app/src/main/scala/org/alephium/explorer/persistence/schema/TokenTxPerAddressSchema.scala b/app/src/main/scala/org/alephium/explorer/persistence/schema/TokenTxPerAddressSchema.scala index 327f76aa0..84c734784 100644 --- a/app/src/main/scala/org/alephium/explorer/persistence/schema/TokenTxPerAddressSchema.scala +++ b/app/src/main/scala/org/alephium/explorer/persistence/schema/TokenTxPerAddressSchema.scala @@ -31,8 +31,10 @@ object TokenPerAddressSchema def pk: PrimaryKey = primaryKey("token_tx_per_address_pk", (txHash, blockHash, address, token)) + def hashIdx: Index = index("token_tx_per_address_hash_idx", txHash) def blockHashIdx: Index = index("token_tx_per_address_block_hash_idx", blockHash) def addressIdx: Index = index("token_tx_per_address_address_idx", address) + def tokenIdx: Index = index("token_tx_per_address_token_idx", token) def tokenAddressIdx: Index = index("token_tx_per_address_token_address_idx", (token, address)) def * : ProvenShape[TokenTxPerAddressEntity] = @@ -51,11 +53,15 @@ object TokenPerAddressSchema } def createIndexes(): DBIO[Unit] = - DBIO.seq() + DBIO.seq( + CommonIndex.blockTimestampTxOrderIndex(this), + CommonIndex.timestampIndex(this) + ) def createConcurrentIndexes()(implicit ec: ExecutionContext): DBActionW[Unit] = for { _ <- createTokenGrouplessAddressIndex() + _ <- createGrouplessIndex() } yield () def createTokenGrouplessAddressIndex(): DBActionW[Int] = @@ -65,5 +71,14 @@ object TokenPerAddressSchema WHERE groupless_address IS NOT NULL; """ + def createGrouplessIndex(): DBActionW[Int] = + sqlu""" + CREATE INDEX CONCURRENTLY IF NOT EXISTS token_tx_per_address_groupless_idx + ON token_tx_per_addresses ( + token, address, groupless_address, block_timestamp, tx_order, tx_hash, block_hash + ) + WHERE groupless_address is not null AND main_chain = true; + """ + val table: TableQuery[TokenPerAddresses] = TableQuery[TokenPerAddresses] } diff --git a/app/src/main/scala/org/alephium/explorer/persistence/schema/TransactionHistorySchema.scala b/app/src/main/scala/org/alephium/explorer/persistence/schema/TransactionHistorySchema.scala index c71662ef7..9bc341580 100644 --- a/app/src/main/scala/org/alephium/explorer/persistence/schema/TransactionHistorySchema.scala +++ b/app/src/main/scala/org/alephium/explorer/persistence/schema/TransactionHistorySchema.scala @@ -23,7 +23,8 @@ object TransactionHistorySchema extends Schema[TransactionHistoryEntity]("transa def pk: PrimaryKey = primaryKey("transactions_history_pk", (intervalType, timestamp, chainFrom, chainTo)) - def timestampIdx: Index = index("transactions_history_timestamp_idx", timestamp) + def intervalTypeIdx: Index = index("transactions_history_interval_type_idx", intervalType) + def timestampIdx: Index = index("transactions_history_timestamp_idx", timestamp) def * : ProvenShape[TransactionHistoryEntity] = (timestamp, chainFrom, chainTo, count, intervalType) diff --git a/app/src/main/scala/org/alephium/explorer/persistence/schema/TransactionPerAddressSchema.scala b/app/src/main/scala/org/alephium/explorer/persistence/schema/TransactionPerAddressSchema.scala index a51416a1b..3b0c9c403 100644 --- a/app/src/main/scala/org/alephium/explorer/persistence/schema/TransactionPerAddressSchema.scala +++ b/app/src/main/scala/org/alephium/explorer/persistence/schema/TransactionPerAddressSchema.scala @@ -31,6 +31,7 @@ object TransactionPerAddressSchema def pk: PrimaryKey = primaryKey("txs_per_address_pk", (txHash, blockHash, address)) + def hashIdx: Index = index("txs_per_address_tx_hash_idx", txHash) def blockHashIdx: Index = index("txs_per_address_block_hash_idx", blockHash) def addressIdx: Index = index("txs_per_address_address_idx", address) def addressTimestampIdx: Index = @@ -53,6 +54,7 @@ object TransactionPerAddressSchema def createIndexes(): DBIO[Unit] = DBIO.seq( + createMainChainIndex(), CommonIndex.blockTimestampTxOrderIndex(this), CommonIndex.timestampIndex(this) ) diff --git a/app/src/main/scala/org/alephium/explorer/persistence/schema/TransactionPerTokenSchema.scala b/app/src/main/scala/org/alephium/explorer/persistence/schema/TransactionPerTokenSchema.scala index 68f8e4080..36ed998df 100644 --- a/app/src/main/scala/org/alephium/explorer/persistence/schema/TransactionPerTokenSchema.scala +++ b/app/src/main/scala/org/alephium/explorer/persistence/schema/TransactionPerTokenSchema.scala @@ -25,6 +25,7 @@ object TransactionPerTokenSchema def pk: PrimaryKey = primaryKey("transaction_per_token_pk", (hash, blockHash, token)) + def hashIdx: Index = index("transaction_per_token_hash_idx", hash) def blockHashIdx: Index = index("transaction_per_token_block_hash_idx", blockHash) def tokenIdx: Index = index("transaction_per_token_token_idx", token) diff --git a/app/src/main/scala/org/alephium/explorer/persistence/schema/TransactionSchema.scala b/app/src/main/scala/org/alephium/explorer/persistence/schema/TransactionSchema.scala index 5e1ef7089..38e7f0b56 100644 --- a/app/src/main/scala/org/alephium/explorer/persistence/schema/TransactionSchema.scala +++ b/app/src/main/scala/org/alephium/explorer/persistence/schema/TransactionSchema.scala @@ -44,6 +44,8 @@ object TransactionSchema extends SchemaMainChain[TransactionEntity]("transaction def timestampIdx: Index = index("txs_timestamp_idx", timestamp) def blockHashIdx: Index = index("txs_block_hash_idx", blockHash) + def chainFromIdx: Index = index("txs_chain_from_idx", chainFrom) + def chainToIdx: Index = index("txs_chain_to_idx", chainTo) def * : ProvenShape[TransactionEntity] = ( diff --git a/app/src/main/scala/org/alephium/explorer/service/IndexChecker.scala b/app/src/main/scala/org/alephium/explorer/service/IndexChecker.scala index 2a441ad17..23c33034f 100644 --- a/app/src/main/scala/org/alephium/explorer/service/IndexChecker.scala +++ b/app/src/main/scala/org/alephium/explorer/service/IndexChecker.scala @@ -33,6 +33,7 @@ object IndexChecker { b <- BlockQueries.explainListMainChainHeadersWithTxnNumber( Pagination.Reversible.unsafe(10000, 20) ) // far page + c <- BlockQueries.explainMainChainQuery() oldestOutputEntity <- OutputQueries.getMainChainOutputs(true).headOrEmpty latestOutputEntity <- OutputQueries.getMainChainOutputs(false).headOrEmpty d <- OutputQueries.explainGetTxnHash(oldestOutputEntity.map(_.key).headOption) @@ -41,6 +42,6 @@ object IndexChecker { latestInputEntity <- InputQueries.getMainChainInputs(false).headOrEmpty f <- InputQueries.explainInputsFromTxs(oldestInputEntity.map(_.hashes())) g <- InputQueries.explainInputsFromTxs(latestInputEntity.map(_.hashes())) - } yield ArraySeq(a, b, d, e, f, g).sortBy(_.passed) + } yield ArraySeq(a, b, c, d, e, f, g).sortBy(_.passed) }