【发布时间】: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