Skip to content

[dbsql] InsertMany Row Batching #212

Merged
peterbroadhurst merged 5 commits intohyperledger:mainfrom
kaleido-io:large-inserts-support
Apr 10, 2026
Merged

[dbsql] InsertMany Row Batching #212
peterbroadhurst merged 5 commits intohyperledger:mainfrom
kaleido-io:large-inserts-support

Conversation

@onelapahead
Copy link
Copy Markdown
Contributor

@onelapahead onelapahead commented Apr 9, 2026

When doing:

INSERT INTO transfers (col1, col2, ..., col17)
VALUES ($1, $2, ..., $17), ($18, ..., $34), ...

Your parameter count in SQL is equal to row * columns.

With bulk inserts for 1000s of rows, with 10+ columns, its easy to end up exceeding the PostgreSQL limit on parameters which is uint16's max - 65535.

So, drawing inspiration from LFDT-Paladin/paladin#644, we also add "batching" of multi-row inserts based on a MaxPlaceholders feature, which will chunk the rows across multiple INSERT's to ensure we're underneath the limit. Not as efficient as PostgreSQL's UNNEST from a performance perspective, but still helps avoid ff-common users from hitting DB limits when inserting in bulk.

… Implementations

Signed-off-by: hfuss <hayden.fuss@kaleido.io>
@onelapahead onelapahead force-pushed the large-inserts-support branch from a09135f to 28bffa8 Compare April 9, 2026 12:50
Signed-off-by: hfuss <hayden.fuss@kaleido.io>
@onelapahead onelapahead changed the title [dbsql] InsertMany Row Batching and Transposed Array Inserts for Compatible SQL Implementations [dbsql] InsertMany Row Batching Apr 9, 2026
Signed-off-by: hfuss <hayden.fuss@kaleido.io>
@onelapahead onelapahead marked this pull request as ready for review April 9, 2026 17:33
@onelapahead onelapahead requested a review from a team as a code owner April 9, 2026 17:33
Signed-off-by: hfuss <hayden.fuss@kaleido.io>
// Use a single multi-row insert
sequences := make([]int64, len(instances))
sequences := allSequences[offset:end]
err := c.DB.InsertTxRows(ctx, c.Table, tx, insert, func() {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noting - if trace logs are enabled, this log line is ridiculously massive when you're inserting in bulk.

Not even useful/readable for mortals or AI:

const maxTraceArgs = 100

func limitTraceArgs(args []interface{}) string {
	if len(args) <= maxTraceArgs {
		return fmt.Sprintf("%+v", args)
	}
	return fmt.Sprintf("%+v ...and %d more", args[:maxTraceArgs], len(args)-maxTraceArgs)
}

func limitTraceSeqs(seqs []int64) string {
	if len(seqs) <= maxTraceArgs {
		return fmt.Sprintf("%v", seqs)
	}
	return fmt.Sprintf("%v ...and %d more", seqs[:maxTraceArgs], len(seqs)-maxTraceArgs)
}

func (s *Database) InsertTxRows(ctx context.Context, table string, tx *TXWrapper, q sq.InsertBuilder, postCommit func(), sequences []int64, requestConflictEmptyResult bool) error {
	l := log.L(ctx)
    // ...
	l.Tracef(`SQL-> insert query: %s (args: %s)`, sqlQuery, limitTraceArgs(args))
// ...
}

could be an approach we should take ? Just whats the limit ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll tackle this another time

Signed-off-by: hfuss <hayden.fuss@kaleido.io>
Copy link
Copy Markdown
Contributor

@peterbroadhurst peterbroadhurst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @onelapahead - I approve of the latest commit to remove the config setting.

Think it's unclear that a config setting of that shape makes sense, given this is a fundamental characteristic we're talking about with the max inserts (rather than a tuning option).

Provider implementations (which FF common doesn't really come with right now) for PSQL and others can have their own config settings.

Also has the benefit of not affecting the builds of consumers, including FF core, FFTM etc.

@peterbroadhurst peterbroadhurst merged commit 075e365 into hyperledger:main Apr 10, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants