Skip to content

Easier batching of bulk inserts #691

@SebastienGllmt

Description

@SebastienGllmt

Summary

Postgres only allows a maximum of u16::MAX input parameters. If you exceed this amount, you will get an error in sqlx. Getting around this limitation while using entities is kind of ugly

Motivation

sea-orm provides a function on entities called insert_many such as the the following example

let apple = cake::ActiveModel {
    name: Set("Apple Pie".to_owned()),
    height: Set(0.5),
    ..Default::default()
};

let insert_result = cake::Entity::insert_many(vec![apple])
     .exec(&db)
     .await?;

This insertion requires two SQL parameters because insert_many uses the VALUES syntax

INSERT INTO `cake` (`name`) VALUES (?), (?)

This works fine up until you hit the u16 limit of parameters. The naive workaround for the Postgres limit would be to do something like this

let inserts = vec![apple];
for chunk in inserts.chunks(u16::MAX as usize) {
    cake::Entity::insert_many(chunk.to_vec()).exec(&db).await?;
}

However, this won't work because we have to divide by the number of columns!

That means the proper solution (as far as I can tell) ends up being

use entity::sea_orm::Iterable;

for chunk in transactions
        .chunks((u16::MAX / <cake::Entity as EntityTrait>::Column::iter().count() as u16) as usize)
    {
    cake::Entity::insert_many(chunk.to_vec()).exec(&db).await?;
}

This is already kind of ugly for a one-time patch in your codebase, but having this kind of chunk logic all over the place makes things even worse

It would be nice if insert_many either handled this for you or if there was some other utility function for this.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions