@@ -37,7 +37,9 @@ import Cardano.Db.Types (DbM)
3737-- RAW INT64 QUERIES (for rollback operations)
3838---------------------------------------------------------------------------
3939
40- -- | Find the minimum ID in a table - returns raw Int64
40+ -- | Find the minimum ID in a table. Fetches all matching IDs (up to 10000)
41+ -- and finds the minimum in Haskell to avoid bad query plans with ORDER BY/MIN.
42+ -- Falls back to the original ORDER BY query if there are too many results.
4143queryMinRefIdStmt ::
4244 forall a b .
4345 DbInfo a =>
@@ -47,8 +49,29 @@ queryMinRefIdStmt ::
4749 HsqlE. Params b ->
4850 -- | Raw ID decoder (Int64)
4951 HsqlD. Row Int64 ->
52+ HsqlStmt. Statement b [Int64 ]
53+ queryMinRefIdStmt fieldName encoder _idDecoder =
54+ HsqlStmt. Statement sql encoder decoder True
55+ where
56+ validCol = validateColumn @ a fieldName
57+ sql =
58+ TextEnc. encodeUtf8 $
59+ Text. concat
60+ [ " SELECT id"
61+ , " FROM " <> tableName (Proxy @ a )
62+ , " WHERE " <> validCol <> " >= $1"
63+ , " LIMIT 10000"
64+ ]
65+ decoder = HsqlD. rowList (HsqlD. column (HsqlD. nonNullable HsqlD. int8))
66+
67+ queryMinRefIdFallbackStmt ::
68+ forall a b .
69+ DbInfo a =>
70+ Text. Text ->
71+ HsqlE. Params b ->
72+ HsqlD. Row Int64 ->
5073 HsqlStmt. Statement b (Maybe Int64 )
51- queryMinRefIdStmt fieldName encoder idDecoder =
74+ queryMinRefIdFallbackStmt fieldName encoder idDecoder =
5275 HsqlStmt. Statement sql encoder decoder True
5376 where
5477 validCol = validateColumn @ a fieldName
@@ -73,8 +96,11 @@ queryMinRefId ::
7396 -- | Parameter encoder
7497 HsqlE. Params b ->
7598 DbM (Maybe Int64 )
76- queryMinRefId fieldName value encoder =
77- runSession mkDbCallStack $ HsqlSes. statement value (queryMinRefIdStmt @ a fieldName encoder rawInt64Decoder)
99+ queryMinRefId fieldName value encoder = do
100+ ids <- runSession mkDbCallStack $ HsqlSes. statement value (queryMinRefIdStmt @ a fieldName encoder rawInt64Decoder)
101+ if length ids >= 10000
102+ then runSession mkDbCallStack $ HsqlSes. statement value (queryMinRefIdFallbackStmt @ a fieldName encoder rawInt64Decoder)
103+ else pure $ if null ids then Nothing else Just (minimum ids)
78104 where
79105 rawInt64Decoder = HsqlD. column (HsqlD. nonNullable HsqlD. int8)
80106
@@ -91,12 +117,33 @@ queryMinRefIdNullableStmt ::
91117 HsqlE. Params b ->
92118 -- | Raw ID decoder (Int64)
93119 HsqlD. Row Int64 ->
120+ HsqlStmt. Statement b [Int64 ]
121+ queryMinRefIdNullableStmt fieldName encoder _idDecoder =
122+ HsqlStmt. Statement sql encoder decoder True
123+ where
124+ validCol = validateColumn @ a fieldName
125+ sql =
126+ TextEnc. encodeUtf8 $
127+ Text. concat
128+ [ " SELECT id"
129+ , " FROM " <> tableName (Proxy @ a )
130+ , " WHERE " <> validCol <> " IS NOT NULL"
131+ , " AND " <> validCol <> " >= $1"
132+ , " LIMIT 10000"
133+ ]
134+ decoder = HsqlD. rowList (HsqlD. column (HsqlD. nonNullable HsqlD. int8))
135+
136+ queryMinRefIdNullableFallbackStmt ::
137+ forall a b .
138+ DbInfo a =>
139+ Text. Text ->
140+ HsqlE. Params b ->
141+ HsqlD. Row Int64 ->
94142 HsqlStmt. Statement b (Maybe Int64 )
95- queryMinRefIdNullableStmt fieldName encoder idDecoder =
143+ queryMinRefIdNullableFallbackStmt fieldName encoder idDecoder =
96144 HsqlStmt. Statement sql encoder decoder True
97145 where
98146 validCol = validateColumn @ a fieldName
99- decoder = HsqlD. rowMaybe idDecoder
100147 sql =
101148 TextEnc. encodeUtf8 $
102149 Text. concat
@@ -107,6 +154,7 @@ queryMinRefIdNullableStmt fieldName encoder idDecoder =
107154 , " ORDER BY id ASC"
108155 , " LIMIT 1"
109156 ]
157+ decoder = HsqlD. rowMaybe idDecoder
110158
111159queryMinRefIdNullable ::
112160 forall a b .
@@ -118,8 +166,11 @@ queryMinRefIdNullable ::
118166 -- | Parameter encoder
119167 HsqlE. Params b ->
120168 DbM (Maybe Int64 )
121- queryMinRefIdNullable fieldName value encoder =
122- runSession mkDbCallStack $ HsqlSes. statement value (queryMinRefIdNullableStmt @ a fieldName encoder rawInt64Decoder)
169+ queryMinRefIdNullable fieldName value encoder = do
170+ ids <- runSession mkDbCallStack $ HsqlSes. statement value (queryMinRefIdNullableStmt @ a fieldName encoder rawInt64Decoder)
171+ if length ids >= 10000
172+ then runSession mkDbCallStack $ HsqlSes. statement value (queryMinRefIdNullableFallbackStmt @ a fieldName encoder rawInt64Decoder)
173+ else pure $ if null ids then Nothing else Just (minimum ids)
123174 where
124175 rawInt64Decoder = HsqlD. column (HsqlD. nonNullable HsqlD. int8)
125176
0 commit comments