【问题标题】:Sqlalcemy - Bulk-insert with multiple cascade & back_populates relationshipsSqlalchemy - 具有多个级联和 back_populates 关系的批量插入
【发布时间】:2022-06-22 02:30:10
【问题描述】:

我试图优化我们对数据库的插入,这目前是瓶颈并减慢了我们的管道。我决定首先启动我们用于测试的 data_generator 加速,一开始所有的表都是空的。认为这将是一个容易开始的地方.. 然后将它们填充并用于各种测试。 目前,我们几乎所有的插入都使用Session.add(入口)或者在某些情况下批量条目add_all(条目),这并没有提高速度。

目标是一次进行更多插入,减少与数据库来回通信的时间,我尝试了各种 bulk_insert 方法(bulk_save_objects、bulk_insert_mappings和 ORM,CORE 方法插入、复制、导入..但我没有什么可以正常工作。外键约束、重复键……或未填充的表。

我将展示一个以前添加的表格示例全部添加()在 run_transaction 中。

class News(NewsBase):
__tablename__ = 'news'

news_id = Column(UUID(as_uuid=True), primary_key=True, nullable=False)
url_visit_count = Column('url_visit_count', Integer, default=0)

# One to many
sab_news = relationship("sab_news", back_populates="news")
sent_news = relationship("SenNews", back_populates="news")
scope_news = relationship("ScopeNews", back_populates="news")
news_content = relationship("NewsContent", back_populates="news")

# One to one
other_news = relationship("other_news", uselist=False, back_populates="news")

# Many to many
companies = relationship('CompanyNews', back_populates='news', cascade="all, delete")
aggregating_news_sources = relationship("AggregatingNewsSource", secondary=NewsAggregatingNewsSource,
                                        back_populates="news")

def __init__(self, title, language, news_url, publish_time):
    self.news_id = uuid4()
    super().__init__(title, language, news_url, publish_time)

我们有很多这样构建的表,其中一些有更多的关系,我现在的结论是,有许多不同的关系,它们相互反向填充和更新,不允许快速的 bulk_insertions,我错了吗?

我目前的解决方案之一是能够将常规 data_generator 的执行时间从 120 秒减少到 15 秒以进行测试,如下所示:

def write_news_to_db(news, news_types, news_sources, company_news,
                 ):
write_bulk_in_chunks(news_types)
write_bulk_in_chunks(news_sources)

def write_news(session):
    enable_batch_inserting(session)
    session.add_all(news)

def write_company_news(session):
    session.add_all(company_news)

engine = create_engine(
        get_connection_string("name"),
        echo = False,
        executemany_mode = "values")

run_transaction(create_session(engine=engine), lambda s: write_news(s))
run_transaction(create_session(), lambda s: write_company_news(s))

我将这个库 sqlalchemy_batch_inserts github 与 Psycopg2 快速执行助手一起使用,设置 executemany_mode="values"。 我通过为这些插入创建一个新引擎来做到这一点 -它确实有效,但这本身似乎是一种不好的做法。它适用于相同的数据库.

无论如何,这似乎确实有效,但它仍然不是我想要的执行速度 - 特别是当我们最初使用空表时。

理想情况下,我不想做这个 hacky 解决方案并避免使用 bulk_insertions,因为 SQLAlchemy 不建议使用它们——以避免我遇到的问题。

但是,在像这样的复杂表的情况下,如何构造查询以正确执行 bulk_insertions - 我们应该重新设计表还是有可能?

在带有 ORM 或 CORE 的 run_transaction 中使用多行插入是理想的,但我无法做到。

任何建议或帮助将不胜感激!

TLDR;具有多个关系、back_populates、级联的批量插入。应该怎么做?

【问题讨论】:

  • 也在 GitHub here 上讨论。

标签: postgresql sqlalchemy insert bulkinsert cockroachdb


【解决方案1】:

CockroachDB 支持对现有表使用多行插入以及对新表使用 IMPORT 语句进行批量插入 - https://www.cockroachlabs.com/docs/stable/insert.html。您是否考虑过直接使用这些选项?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-03-28
    • 2018-06-25
    • 2021-03-09
    • 1970-01-01
    • 2019-05-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多