From e63deae5a3c0c7af7befff8609361e3bd81f8bdf Mon Sep 17 00:00:00 2001 From: kderme Date: Mon, 23 Mar 2026 16:34:55 +0200 Subject: [PATCH 1/2] Make sure we're using indexes during rollbacks Fixes https://github.com/IntersectMBO/cardano-db-sync/issues/2083 The `queryMinRefId` query uses ```sql SELECT id FROM WHERE >= $1 ORDER BY id ASC LIMIT 1. ``` The planner sometimes picks a bad plan: ```sql Index Scan using tx_pkey on tx Filter: (block_id >= $1) ``` the filter is not Index Cond, so this ends up in a sequential scan. The index refers to the primary key and is only used for sorting. Instead we use a simpler query without ORDER BY: SELECT id FROM
WHERE >= $1 LIMIT 10000 This forces the planner to use the field's index. The results are fetched and the minimum is found in Haskell. Near the tip this returns only a handful of rows. If there are more than 10000 matching rows (large rollback), we fall back to the original ORDER BY id ASC LIMIT 1 query. --- cardano-db/src/Cardano/Db/Operations/Query.hs | 43 ++++++++++++++++++- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/cardano-db/src/Cardano/Db/Operations/Query.hs b/cardano-db/src/Cardano/Db/Operations/Query.hs index 904ed1646..17b7422d1 100644 --- a/cardano-db/src/Cardano/Db/Operations/Query.hs +++ b/cardano-db/src/Cardano/Db/Operations/Query.hs @@ -581,6 +581,45 @@ queryMinRefId :: field -> ReaderT SqlBackend m (Maybe (Key record)) queryMinRefId txIdField txId = do + res <- select $ do + rec <- from $ table @record + where_ (rec ^. txIdField >=. val txId) + limit 10000 + pure $ rec ^. persistIdField + if length res >= 10000 + then queryMinRefIdFallback txIdField txId + else pure $ minimumMay $ map unValue res + where + minimumMay [] = Nothing + minimumMay xs = Just (minimum xs) + +queryMinRefIdNullable :: + forall m field record. + (MonadIO m, PersistEntity record, PersistField field) => + EntityField record (Maybe field) -> + field -> + ReaderT SqlBackend m (Maybe (Key record)) +queryMinRefIdNullable txIdField txId = do + res <- select $ do + rec <- from $ table @record + where_ (isJust (rec ^. txIdField)) + where_ (rec ^. txIdField >=. just (val txId)) + limit 10000 + pure $ rec ^. persistIdField + if length res >= 10000 + then queryMinRefIdNullableFallback txIdField txId + else pure $ minimumMay $ map unValue res + where + minimumMay [] = Nothing + minimumMay xs = Just (minimum xs) + +queryMinRefIdFallback :: + forall m field record. + (MonadIO m, PersistEntity record, PersistField field) => + EntityField record field -> + field -> + ReaderT SqlBackend m (Maybe (Key record)) +queryMinRefIdFallback txIdField txId = do res <- select $ do rec <- from $ table @record where_ (rec ^. txIdField >=. val txId) @@ -589,13 +628,13 @@ queryMinRefId txIdField txId = do pure $ rec ^. persistIdField pure $ unValue <$> listToMaybe res -queryMinRefIdNullable :: +queryMinRefIdNullableFallback :: forall m field record. (MonadIO m, PersistEntity record, PersistField field) => EntityField record (Maybe field) -> field -> ReaderT SqlBackend m (Maybe (Key record)) -queryMinRefIdNullable txIdField txId = do +queryMinRefIdNullableFallback txIdField txId = do res <- select $ do rec <- from $ table @record where_ (isJust (rec ^. txIdField)) From 39c66dbebb3f303da2a3a716a61e187fa91f097e Mon Sep 17 00:00:00 2001 From: kderme Date: Tue, 24 Mar 2026 01:16:54 +0200 Subject: [PATCH 2/2] Prepare release 13.6.0.7 --- CHANGELOG.md | 3 +++ cardano-chain-gen/cardano-chain-gen.cabal | 2 +- cardano-db-sync/cardano-db-sync.cabal | 2 +- cardano-db-tool/cardano-db-tool.cabal | 2 +- cardano-db/cardano-db.cabal | 2 +- cardano-db/test/cardano-db-test.cabal | 2 +- cardano-smash-server/cardano-smash-server.cabal | 2 +- docker-compose.example.yml | 2 +- docker-compose.yml | 2 +- 9 files changed, 11 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c3a2da4b5..3f7199654 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Revision history for cardano-db-sync +## 13.6.0.7 +- Fix slow rollbacks caused by suboptimal query plans on large tables [#2083] + ## 13.6.0.5 - Fix offchain data so it supports files up to 3MB [#1928] - Upgrade to PostgreSQL 17 diff --git a/cardano-chain-gen/cardano-chain-gen.cabal b/cardano-chain-gen/cardano-chain-gen.cabal index 999f25eaa..333caf7c9 100644 --- a/cardano-chain-gen/cardano-chain-gen.cabal +++ b/cardano-chain-gen/cardano-chain-gen.cabal @@ -1,7 +1,7 @@ cabal-version: 3.6 name: cardano-chain-gen -version: 13.6.0.5 +version: 13.6.0.7 synopsis: A fake chain generator for testing cardano DB sync. description: A fake chain generator for testing cardano DB sync. homepage: https://github.com/IntersectMBO/cardano-db-sync diff --git a/cardano-db-sync/cardano-db-sync.cabal b/cardano-db-sync/cardano-db-sync.cabal index 636225d7f..da117f068 100644 --- a/cardano-db-sync/cardano-db-sync.cabal +++ b/cardano-db-sync/cardano-db-sync.cabal @@ -1,7 +1,7 @@ cabal-version: 3.6 name: cardano-db-sync -version: 13.6.0.5 +version: 13.6.0.7 synopsis: The Cardano DB Sync node description: A Cardano node that follows the Cardano chain and inserts data from the chain into a PostgresQL database. diff --git a/cardano-db-tool/cardano-db-tool.cabal b/cardano-db-tool/cardano-db-tool.cabal index 3dc10238b..d17ab9017 100644 --- a/cardano-db-tool/cardano-db-tool.cabal +++ b/cardano-db-tool/cardano-db-tool.cabal @@ -1,7 +1,7 @@ cabal-version: 3.6 name: cardano-db-tool -version: 13.6.0.5 +version: 13.6.0.7 synopsis: Utilities to manage the cardano-db-sync databases. description: Utilities and executable, used to manage and validate the PostgreSQL db and the ledger database of the cardano-db-sync node diff --git a/cardano-db/cardano-db.cabal b/cardano-db/cardano-db.cabal index 9d21ae292..c3f071105 100644 --- a/cardano-db/cardano-db.cabal +++ b/cardano-db/cardano-db.cabal @@ -1,7 +1,7 @@ cabal-version: 3.6 name: cardano-db -version: 13.6.0.5 +version: 13.6.0.7 synopsis: A base PostgreSQL component for the cardano-db-sync node. description: Code for the Cardano DB Sync node that is shared between the cardano-db-node and other components. diff --git a/cardano-db/test/cardano-db-test.cabal b/cardano-db/test/cardano-db-test.cabal index cbff16efa..883bec7c8 100644 --- a/cardano-db/test/cardano-db-test.cabal +++ b/cardano-db/test/cardano-db-test.cabal @@ -1,7 +1,7 @@ cabal-version: 3.6 name: cardano-db-test -version: 13.6.0.5 +version: 13.6.0.7 synopsis: Tests for the base functionality of the cardano-db library description: Code for the Cardano DB Sync node that is shared between the cardano-db-node and other components. diff --git a/cardano-smash-server/cardano-smash-server.cabal b/cardano-smash-server/cardano-smash-server.cabal index 338617fc1..fb8832bc5 100644 --- a/cardano-smash-server/cardano-smash-server.cabal +++ b/cardano-smash-server/cardano-smash-server.cabal @@ -1,7 +1,7 @@ cabal-version: 3.6 name: cardano-smash-server -version: 13.6.0.5 +version: 13.6.0.7 synopsis: The Cardano smash server description: Please see the README on GitHub at diff --git a/docker-compose.example.yml b/docker-compose.example.yml index 39d2039b3..06c3800f1 100644 --- a/docker-compose.example.yml +++ b/docker-compose.example.yml @@ -59,7 +59,7 @@ services: max-file: "10" cardano-db-sync: - image: ghcr.io/intersectmbo/cardano-db-sync:13.6.0.5 + image: ghcr.io/intersectmbo/cardano-db-sync:13.6.0.7 environment: - NETWORK=${NETWORK:-mainnet} - POSTGRES_HOST=postgres diff --git a/docker-compose.yml b/docker-compose.yml index 9b8d9200a..dc372e00d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -54,7 +54,7 @@ services: max-file: "10" cardano-db-sync: - image: ghcr.io/intersectmbo/cardano-db-sync:13.6.0.5 + image: ghcr.io/intersectmbo/cardano-db-sync:13.6.0.7 environment: - DB_SYNC_CONFIG=${DB_SYNC_CONFIG:-} - DISABLE_LEDGER=${DISABLE_LEDGER}