【发布时间】:2021-04-01 07:12:51
【问题描述】:
我有 1,000,000 条记录要输入到数据库中,遗憾的是其中一些记录不支持 db 模式。在记录失败的那一刻我正在做:
- 回滚到数据库
- 观察异常
- 解决问题
- 再次运行。 我希望构建一个脚本来保存所有“坏”记录,但会提交所有正确的记录。
当然,我可以一个一个地提交,然后当提交失败时回滚并提交下一个,但我会支付“运行时价格”,因为代码会运行很长时间。
在下面的示例中,我有两个模型:文件和客户端。一个客户端有很多文件的关系。 在 commit.py 文件中,我希望一次或分批(1k)提交 1M 个文件对象。目前我只知道当我最后提交失败时,有没有办法知道之前哪个对象是“坏的”(以外键为例的完整性错误),即停放一边(在另一个列表中)但是承诺所有的“好”
非常感谢您的帮助
#model.py
from sqlalchemy import Column, DateTime, String, func, Integer, ForeignKey
from . import base
class Client(base):
__tablename__ = 'clients'
id = Column(String, primary_key=True)
class File(base):
__tablename__ = 'files'
id = Column(Integer, primary_key=True, autoincrement=True)
client_id = Column(String, ForeignKey('clients.id'))
path = Column(String)
#init.py
import os
from dotenv import load_dotenv
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
load_dotenv()
db_name = os.getenv("DB_NAME")
db_host = os.getenv("DB_HOST")
db_port = os.getenv("DB_PORT")
db_user = os.getenv("DB_USER")
db_password = os.getenv("DB_PASSWORD")
db_uri = 'postgresql://' + db_user + ':' + db_password + '@' + db_host + ':' + db_port + '/' + db_name
print(f"product_domain: {db_uri}")
base = declarative_base()
engine = create_engine(db_uri)
base.metadata.bind = engine
Session = sessionmaker(bind=engine)
session = Session()
conn = engine.connect()
#commit.py
from . import session
def commit(list_of_1m_File_objects_records):
#I wish to for loop over the rows and if a specific row rasie excaption to insert it to a list and handle after wards
for file in list_of_1m_File_objects_records:
session.add(file)
session.commit()
# client:
# id
# "a"
# "b"
# "c"
# file:
# id|client_id|path
# --|---------|-------------
# 1 "a" "path1.txt"
# 2 "aa" "path2.txt"
# 3 "c" "path143.txt"
# 4 "a" "pat.txt"
# 5 "b" "patb.txt"
# wish the file data would enter the database although it has one record "aa" which will raise integrity error
【问题讨论】:
-
所以您遇到的错误是完整性错误。我们可以假设您的 1m 行的来源不会引入完整性错误吗?即,您的数据在 id 上是唯一的吗?我很少使用 sqlalchemy,但在我看来,数据库服务器无法发现完整性错误,直到您尝试写入数据库。下面,有人建议您先检查现有记录。循环结束时的 session.commit 很快,因为它延迟了数据库写入。或者 session.merge() 可能很有趣。见stackoverflow.com/a/26018934/401226
-
相反,我们可以假设 1M 行之一导致错误。在那种情况下,最快的提交方式是什么?
-
如果你想用新行更新数据库以防完整性错误,你可以试试 session.merge
-
... 或采用以下建议:通过查询获取所有现有 ID,将它们放入 python set() 并在执行 session.add() 之前检查 ID。这可能是最快的方式。
标签: python postgresql sqlalchemy