- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
全部,
我正在读取一个 csv 文件并使用 sqlalchemy 将数据添加到 MySQL 数据库。其中一个表是地址表,它应该只保存唯一的地址。这些地址与另一个“语句”表之间存在关系,该表具有地址id的外键字段。
因此,对于我的数据文件中的每一行,我创建一个新的语句 obj,然后获取关联地址的 ID。如果地址已经存在,则返回该 ID。否则,我创建一个新地址 obj 并返回该 id。这是使用以下代码完成的,改编自 this SO question .
def get_or_create(self, model, rec):
instance = self.session.query(model).filter_by(**dict(filter(lambda (x,y): x in model.__dict__.keys(), rec.iteritems()))).first()
if instance:
return instance
else:
instance = model(rec)
return instance
我在我的 id 字段中使用 GUID,它是地址表主键的一部分:
class address(Base):
__tablename__ = 'address'
id = id_column()
name = Column(String(75), primary_key=True)
Address_Line_One = Column(String(50), primary_key=True)
Address_Line_Two = Column(String(50), primary_key=True)
Address_Line_Three = Column(String(50), primary_key=True)
Address_Line_Four = Column(String(50), primary_key=True)
id_column()
来自 here ,尽管由于其他地方的限制,它已被转换为 CHAR(32)
。最后,这里有一个片段:
currStatement = statements(rec, id=currGUID)
currStatement.address = self.get_or_create(address, rec)
这一切都很好,只是速度很慢。对于在一个事务中插入的约 65,000 条语句,我看到在干净的测试数据库上插入时间为 1.5 小时。实时观察插入显示它很快达到约 10,000 行,然后插入速度开始下降。
我可以做些什么来加快这个插入时间?
编辑:
经过进一步测试,我发现插入时间慢的部分原因是每个对象都是单独插入的。所以,我有大约 65,000 行,每一行都变成了几个单独插入的 sqlalchemy 对象。使用 sqlalchemy 0.7,如何批量插入我的对象?
最佳答案
好的!
所以答案是我单独插入每一行,并在每次地址检查时往返于数据库。地址检查是最糟糕的部分,因为它的速度呈指数级下降。我计算出插入原始数据(1.5 小时),然后再次插入相同的数据,将花费 ~9 小时!
所以这个答案将讨论我为转换成批量插入语句所做的工作,以及一些需要注意的事情。
ORM 很棒,但要意识到它与批量插入并不完全吻合。批量插入需要在 session 中使用较低级别的 execute
语句。这些不将 ORM 对象作为输入,而是一个字典列表和一个 insert
对象。因此,如果您将充满行的 csv 文件转换为 ORM 对象,则需要NOT将它们添加到当前 session 中,而是将它们转换为字典以备后用。
def asdict(obj):
return dict((col.name, getattr(obj, col.name))
for col in class_mapper(obj.__class__).mapped_table.c)
currGUID = uuid.uuid4()
currPrintOrMail = printOrMail(rec, id=currGUID)
currStatement = statements(rec, id=currGUID)
currAddress = self.get_or_create(address, rec)
currStatement.address = currAddress
self.currPrintOrMail_bulk.append(asdict(currPrintOrMail))
self.currStatement_bulk.append(asdict(currStatement))
asdict方法来自here .这使您可以创建 ORM 对象中列的字典。它们永远不会被添加到 session 中,并在不久之后从内存中消失。
如果你已经建立了ORM关系:
class statements(Base):
__tablename__ = 'statements'
id = id_column()
county = Column(String(50),default='',nullable=False)
address_id = Column(CHAR(36), ForeignKey('address.id'))
address = relationship("address", backref=backref("statements", cascade=""))
printOrMail_id = Column(CHAR(36), ForeignKey('printOrMail.id'))
pom = relationship("printOrMail", backref=backref("statements", cascade=""))
property_id = Column(CHAR(36), ForeignKey('property.id'))
prop = relationship("property", backref=backref("statements", cascade=""))
确保 cascade 在 backref 中为空!否则,将关系中的对象插入到 session 中将 cascade 通过其余的对象。当您稍后尝试批量插入您的值时,它们将作为重复项被拒绝......如果您幸运的话。
这很重要,因为部分要求是获取有效地址的 address_id(如果存在)并添加地址(如果不存在)。由于查询往返非常慢,我将 get_or_create
更改为:
def get_or_create(self, model, rec):
"""Check if current session has address. If not, query DB for it. If no one has the address, create and flush a new one to the session."""
instance = self.session.query(model).get((rec['Name'], rec['Address_Line_One'], rec['Address_Line_Two'], rec['Address_Line_Three'], rec['Address_Line_Four']))
if instance:
return instance
else:
instance = model(rec)
self.session.add(instance)
self.session.flush()
return instance
使用 get
会导致 sqlalchemy 首先检查 session ,防止跨网络传输。但是,它只有在 新 地址被添加到 session 中时才有效!还记得关系吗?这是级联到语句的插入中。此外,如果您没有 flush()
或有 autoflush=True
,则 get
无法看到新添加的对象。
创建 session 时,保留您的对象!
self.session = sessionmaker(autoflush=False, expire_on_commit=False)
如果您不包含 expire_on_commit=False
,那么您将丢失您的地址,并再次开始往返。
现在我们已经有了要插入的 ORM 对象的字典列表。但是我们还需要一个插入对象。
self.session.execute(printOrMail.__table__.insert(), self.currPrintOrMail_bulk)
self.session.execute(statements.__table__.insert(), self.currStatement_bulk)
Buried in the docs ,似乎可以使用 classname.__table__
作为必要的表对象,insert 要求.因此,在 session 中,使用 ORM 类获取表以获取插入对象,使用字典列表运行执行。不要忘记事后提交!
这将使您能够成功地将批量插入和 ORM 与关系混合并查询 sqlalchemy 中的唯一条目。只要注意内存不足。我不得不一次批量插入 ~30,000
记录,否则 py2.7(32bit)
会在使用大约 2G
时崩溃。
关于mysql - 使用 sqlalchemy 检查行和返回 id 的存在很慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9165462/
目前我正在构建相当大的网络系统,我需要强大的 SQL 数据库解决方案。我选择 Mysql 而不是 Postgres,因为一些任务需要只读(MyISAM 引擎)而其他任务需要大量写入(InnoDB)。
我在 mysql 中使用如下命令。当它显示表格数据时,它被格式化为一个非常干净的表格,间距均匀且 |作为列分隔符。 SELECT * FROM TABLE_NAME; 当我从 CLI 运行命令时,如下
我知道这个问题之前已经被问过好几次了,我已经解决了很多问题,但到目前为止没有任何效果。 MySQL 试图将自身安装到的目录 (usr/local/mysql) 肯定有问题。关于我的错误的奇怪之处在于我
以下是我的 SQL 数据结构,我正在尝试如下两个查询: Select Wrk_ID, Wrk_LastName, Skill_Desc from Worker, Skill where
我们有一个本地 mysql 服务器(不在公共(public)域上),并希望将该服务器复制到我们拥有的 google 云 sql 实例。我的问题是:1.这可能吗?2.我们的本地服务器只能在本地网络上访问
我有一个表(test_table),其中一些字段值(例如字段 A、B 和 C)是从外部应用程序插入的,还有一个字段(字段 D),我想从现有表(store_table)插入其值,但在插入前者(A、B 和
我想创建一个 AWS RDS 实例,然后使用 terraform 管理数据库用户。因此,首先,我创建了一个 RDS 实例,然后使用创建的 RDS 实例初始化 mysql 提供程序,以进一步将其用于用户
当用户在我的网站上注册时,他们会在我的一个数据库中创建自己的表格。该表存储用户发布的所有帖子。我还想做的是也为他们生成自己的 MySql 用户——该用户仅有权从他们的表中读取、写入和删除。 创建它应该
我有一个关于 ColdFusion 和 Mysql 的问题。我有两个表:PRODUCT 和 PRODUCT_CAT。我想列出包含一些标记为:IS_EXTRANET=1 的特殊产品的类别。所以我写了这个
我想获取 recipes_id 列的值,以获取包含 ingredient_id 的 2,17 和 26 条目的值。 假设 ingredient_id 2 丢失则不获取记录。 我已经尝试过 IN 运算符
在 Ubuntu 中,我通常安装两者,但 MySQL 的客户端和服务器之间有什么区别。 作为奖励,当一个新语句提到它需要 MySQL 5.x 时,它是指客户端、服务器还是两者兼而有之。例如这个链接ht
我重新访问了我的数据库并注意到我有一些 INT 类型的主键。 这还不够独特,所以我想我会有一个指导。 我来自微软 sql 背景,在 ssms 中你可以 选择类型为“uniqeidentifier”并自
我的系统上有 MySQL,我正在尝试确定它是 Oracle MySQL 还是 MySQL。 Oracle MySQL 有区别吗: http://www.oracle.com/us/products/m
我是在生产 MySQL 中运行的应用程序的新维护者。之前的维护者已经离开,留下的文档很少,而且联系不上了。 我面临的问题是执行以下请求大约需要 10 秒: SELECT COUNT(*) FROM `
我有两个位于不同机器上的 MySQL 数据库。我想自动将数据从一台服务器传输到另一台服务器。比方说,我希望每天早上 4:00 进行数据传输。 可以吗?是否有任何 MySQL 内置功能可以让我们做到这一
有什么方法可以使用 jdbc 查询位于 mysql 根目录之外的目录中的 mysql 表,还是必须将它们移动到 mysql 根目录内的数据库文件夹中?我在 Google 上搜索时没有找到任何东西。 最
我在 mysql 数据库中有两个表。成员和 ClassNumbers。两个表都有一个付费年份字段,都有一个代码字段。我想用代码数字表中的值更新成员表中的付费年份,其中成员中的代码与 ClassNumb
情况:我有 2 台服务器,其中一台当前托管一个实时 WordPress 站点,我希望能够将该站点转移到另一台服务器,以防第一台服务器出现故障。传输源文件很容易;传输数据库是我需要弄清楚如何做的。两台服
Phpmyadmin 有一个功能是“复制数据库到”..有没有mysql查询来写这个函数?类似于将 db A 复制到新的 db B。 最佳答案 首先创建复制数据库: CREATE DATABASE du
我有一个使用 mySQL 作为后端的库存软件。我已经在我的计算机上对其进行了测试,并且运行良好。 当我在计算机上安装我的软件时,我必须执行以下步骤: 安装 mySQL 服务器 将用户名指定为“root
我是一名优秀的程序员,十分优秀!