我正在写一个Django ORM增强,试图缓存模型,并将模型保存推迟到事务结束.一切都快完成了,但我在SQL语法方面遇到了意想不到的困难.

我不太擅长DBA,但据我所知,对于许多小查询,数据库并不能真正有效地工作.很少有更大的问题比这更好.例如,最好使用大批量插入(比如一次插入100行)而不是100行一行.

现在,在我看来,SQL并没有提供任何语句来对表执行批处理更新.这个词似乎是confusing,所以,我会解释我的意思.我有一个任意数据数组,每个条目描述表中的一行.我想更新表中的某些行,每个行都使用数组中相应条目中的数据.这个 idea 非常类似于批量插入.

例如:我的表可以有两列"id""some_col".现在,描述批量更新数据的数组由三个条目(1, 'first updated')(2, 'second updated')(3, 'third updated')组成.更新之前,表中包含行:(1, 'first')(2, 'second')(3, 'third').

我是通过这个帖子来的:

Why are batch inserts/updates faster? How do batch updates work?

这似乎是我想要的,但我无法真正理解最后的语法.

我还可以删除所有需要更新的行,并使用批插入重新插入它们,但我发现很难相信这实际上会表现得更好.

我使用PostgreSQL 8.4,所以这里也可以使用一些存储过程.然而,随着我计划最终开放该项目的源代码,任何在不同的RDBMS上做同样事情的可移植 idea 或方法都是最受欢迎的.

Follow up question:如何批量执行"插入或更新"/"插入"语句?

Test results

我在4个不同的表上执行了100次10次插入操作(总共1000次插入).我在Django 1.3上测试了PostgreSQL 8.4后端.

结果如下:

  • 通过Django ORM完成的所有操作-每个通过~2.45 seconds次,
  • 同样的操作,但没有Django ORM——每次通过~1.48 seconds次,
  • 仅插入操作,不查询数据库中的序列值~0.72 seconds
  • 仅插入操作,以10块(总共~0.19 seconds块)的形式执行~0.19 seconds
  • 只有插入操作,一个大的执行块~0.13 seconds.
  • 仅插入操作,每个块大约250条语句,~0.12 seconds条.

结论:在一个连接中执行尽可能多的操作.执行().Django本身带来了巨大的开销.

免责声明:除了默认主键索引,我没有引入任何索引,因此插入操作可能会因此运行得更快.

推荐答案

我在批量事务性工作中使用了3种策略:

  1. 动态生成SQL语句,用分号连接它们,然后一次性提交语句.我已经用这种方式做了多达100次的插入,而且非常有效(针对Postgres).
  2. JDBC具有内置的批处理功能(如果已配置).如果生成事务,可以刷新JDBC语句,以便它们一次完成事务.这种策略需要更少的数据库调用,因为语句都是在一个批中执行的.
  3. Hibernate还支持JDBC批处理,就像前面的例子一样,但是在本例中,您对Hibernate Session执行flush()方法,而不是对底层JDBC连接执行flush()方法.它实现了与JDBC批处理相同的功能.

顺便说一句,Hibernate还支持集合获取中的批处理策略.如果用@BatchSize注释一个集合,那么在获取关联时,Hibernate将使用IN而不是=,从而导致加载集合的语句减少SELECT条.

Sql相关问答推荐

如何在PostgreSQL中同时为id s列表执行多个update语句?'

表名数组

使用SQL/R循环查找邻居

将SEMI JOIN、ANTI JOIN转换为非连接SQL

解析键-值对,根据值 Select ,并使用SQL创建新列

在甲骨文中查找前一个星期一的S日期

PostgreSQL中的合并命令是原子的,还是需要一些类似于SQL Server版本的内容?

DBeaver将过程中的属性列表转换为字符串

SQL到Snowflake-转换嵌套的SELECT(值

改进的SQL子字符串提取

每个学校 Select N个最新的行,但跳过同一学生的重复行

同时插入和更新记录

向表中添加新列取决于表的日期列(unpivot)

除了风格之外,还有什么理由更喜欢简单的CASE WHEN而不是搜索呢?

PostgreSQL:从多个字段收集特定指标的最后一个条目

如何获取每个组中最近的n条记录并将它们聚合成数组

如何通过CROSS APPLY获取多级嵌套JSON属性的值?

在多个表上递归查找

SQL:如何从时间戳数据生成时间序列并计算不同事件类型的累计总和?

在 SQL 的每行选项中 Select 最大值