【问题标题】:SQLAlchemy: Many to many cascade example from docs is super slowSQLAlchemy:来自文档的多对多级联示例非常慢
【发布时间】:2021-08-17 02:57:13
【问题描述】:

免责声明:我是数据库新手,这是我在 StackOverflow 上的第一个问题。很高兴编辑以使其尽可能清晰和符合代码。

在我的应用程序中,我有两个表:InputData(我的应用程序下载的外部数据)和 OutputData(我的应用程序创建的数据)。一个或多个 InputData 可用于创建一个或多个 OutputData,当一个 InputData 项目被删除时,我想删除所有使用已删除项目作为输入创建的 OutputData。本质上是与级联删除的多对多关联。

对我来说很幸运,至少我是这么想的,the SQLAlchemy docs 中有一个我想做的确切示例。然而,在实现它并使用它之后,我发现它非常慢。

我做了一些基准测试,发现 100,000 个 InputData,每个都有一个 OutputData 子项(总共 100,000 个 OutputData)需要将近 10 分钟才能删除。相比之下,具有级联删除功能的一对多模型只需 30 秒即可删除数量级大的表。

经过大量研究,我真的只有两个想法:

  1. 我对多对多级联的成本非常幼稚,实际上删除 2 个表中的 200,000 行需要 10 分钟是有道理的。
  2. 删除 InputData 项时,将遍历整个 OutputData 表以检查哪些 OutputData 行引用了已删除项作为其父项。这在我的直觉中当然是有道理的,特别是因为我读过有关 Postgres 不会自动在外键上创建索引的文章,但我找不到任何人遇到相同问题或如何解决它的示例。
  3. 我删除的方式不对。上述基准只是
db.session.query(InputData).delete()
db.session.commit()

我的表格(正是来自不同名称的文档):

association_table = Table('association', Base.metadata,
    Column('input_data_id', Integer, ForeignKey('input_data.id', ondelete="CASCADE")),
    Column('output_data_id', Integer, ForeignKey('output_data.id', ondelete="CASCADE"))
)

class InputData(Base):
    __tablename__ = 'input_data'
    id = Column(Integer, primary_key=True)
    children = relationship(
        "OutputData",
        secondary=association_table,
        back_populates="inputs",
        cascade="all, delete",
    )

class OutputData(Base):
    __tablename__ = 'output_data'
    id = Column(Integer, primary_key=True)
    parents = relationship(
        "InputData",
        secondary=association_table,
        back_populates="outputs",
        passive_deletes=True
    )

提前谢谢你!

【问题讨论】:

    标签: python postgresql sqlalchemy flask-sqlalchemy


    【解决方案1】:

    好吧,删除级联本质上是每条记录,这使得删除操作超级慢(或更新)

    而您可以使用单独的删除语句从每组表中删除,这比级联删除快得多。

    因此,虽然级联删除更方便同时删除一条记录而不是很多记录,但如果要删除一组记录,手动删除将是更好的方法。

    无论哪种方式,在外键上添加索引都会提高删除的性能。

    【讨论】:

    • 非常感谢您的反馈。由于它是多对多关系,我应该有两个索引吗?单程一个?
    • 不客气。 Fk 列上的每个表都需要一个索引
    猜你喜欢
    • 2018-12-10
    • 1970-01-01
    • 2014-08-30
    • 2016-03-02
    • 1970-01-01
    • 1970-01-01
    • 2021-06-15
    • 1970-01-01
    • 2011-11-10
    相关资源
    最近更新 更多