sqlalchemy bulk_insert_mappings生成大量插入批次,这是可以避免的吗?

时间:2018-02-19 21:53:43

标签: python database performance optimization sqlalchemy

我有大量的对象需要通过sqlalchemy插入到Oracle数据库中。

使用单个插件需要很长时间才能执行。在搜索之后,很明显有更高效的批量插入方法,bulk_insert_mappings,bulk_save_objects等。这些方法比单个插入更好。但是,我注意到他们似乎将插入批处理大约8个左右的分组。是否可以将批量大小增加到1000左右?

我一直在使用的效果文档是:http://docs.sqlalchemy.org/en/latest/faq/performance.html

render_nulls标志似乎没有效果。 如果有帮助,我正在使用cx_Oracle驱动程序。

供额外参考:

session.bulk_insert_mappings(MY_OBJECT, my_object_dicts_for_insert)

生成关于len(my_object_dicts_for_insert)/ 8语句,由“after_cursor_execute”事件测量。有没有办法从sqlalchemy或数据库中调整这种行为?

谢谢!

1 个答案:

答案 0 :(得分:3)

发现问题,这是我对render_nulls标志的理解。

从描述中,我认为如果提供了具有不同键的字典列表,那么它们将用空值填充以允许单个插入语句。

这不是它的工作原理,您必须确保您的词典列表具有相同的键,并且您使用无键填充未使用的字段。然后,当render_nulls设置为True时,将使用None值将空值插入到列中,从而允许单个insert语句。

示例:

# This results in 2 inserts
my_objects = [{'a': 1, 'b': 2}, {'a': 1}]
session.bulk_insert_mappings(MY_OBJECT, my_objects, render_nulls=True)

# This results in 2 inserts
my_objects = [{'a': 1, 'b': 2}, {'a': 1}]
session.bulk_insert_mappings(MY_OBJECT, my_objects, render_nulls=False)

# This results in 2 inserts
my_object = [{'a': 1, 'b': 2}, {'a': 1, 'b': None}]
session.bulk_insert_mappings(MY_OBJECT, my_objects, render_nulls=False)

# This results in 1 insert - BETTER PERFORMANCE
my_object = [{'a': 1, 'b': 2}, {'a': 1, 'b': None}]
session.bulk_insert_mappings(MY_OBJECT, my_objects, render_nulls=True)

这导致相当大的性能提升,对我来说性能提高了大约10倍。

请注意,使用render_nulls时可能会出现副作用,请阅读此处的文档:http://docs.sqlalchemy.org/en/latest/orm/session_api.html#sqlalchemy.orm.session.Session.bulk_insert_mappings

如果您无法使用render_nulls标志,无法使用None填充您的dicts,或者不希望增加发送空值的带宽,则可以通过将对象列表分组来增加执行的插入数量dict键集。

实施例

# This will result in 2 inserts - BETTER PERFORMANCE
my_objects = [{'a': 1, 'b': 2}, {'a': 2, 'b': 3}, {'a': 4}]
session.bulk_insert_mappings(MY_OBJECT, my_objects)
# This will result in 3 inserts
my_objects = [{'a': 1, 'b': 2}, {'a': 4}, {'a': 2, 'b': 3}]
session.bulk_insert_mappings(MY_OBJECT, my_objects)