jul*_*icz 45 sql database postgresql insert sql-update
我正在编写一个Django-ORM增强版,它尝试缓存模型并推迟模型保存直到事务结束.这几乎已经完成,但是我在SQL语法中遇到了意想不到的困难.
我不是一个DBA,但据我所知,数据库并不能真正有效地处理许多小问题.几个更大的查询要好得多.例如,最好使用大批量插入(比如一次100行)而不是100个单行.
现在,从我所看到的,SQL并没有真正提供任何语句来对表执行批量更新.这个词似乎令人困惑,我会解释我的意思.我有一个任意数据数组,每个条目描述一个表中的一行.我想更新表中的某些行,每个行都使用数组中相应条目的数据.这个想法非常类似于批量插入.
例如:我的表可以有两列"id"和"some_col".现在描述用于在批处理更新的数据阵列由三个条目的(1, 'first updated'),(2, 'second updated')和(3, 'third updated').更新前表中包含行:(1, 'first'),(2, 'second'),(3, 'third').
我来到这篇文章:
这似乎做我想要的,但我最终无法弄清楚语法.
我还可以删除所有需要更新的行,并使用批量插入重新插入它们,但我发现很难相信这实际上会更好.
我使用PostgreSQL 8.4,因此这里也可以使用一些存储过程.然而,当我计划最终开源项目时,任何更便携的想法或方法在不同的RDBMS上做同样的事情是最受欢迎的.
后续问题:如何批量"插入或更新"/"upsert"语句?
检测结果
我已经执行了100次10次插入操作,分布在4个不同的表中(总共1000个插入).我使用PostgreSQL 8.4后端在Django 1.3上进行了测试.
这些是结果:
结论:在单个connection.execute()中执行尽可能多的操作.Django本身带来了巨大的开销.
免责声明:除了默认主键索引之外,我没有引入任何索引,因此插入操作可能会因此而运行得更快.
hag*_*llo 61
您可以通过Ketema修改三列的批量插入:
INSERT INTO "table" (col1, col2, col3)
VALUES (11, 12, 13) , (21, 22, 23) , (31, 32, 33);
Run Code Online (Sandbox Code Playgroud)
它成为了:
INSERT INTO "table" (col1, col2, col3)
VALUES (unnest(array[11,21,31]),
unnest(array[12,22,32]),
unnest(array[13,23,33]))
Run Code Online (Sandbox Code Playgroud)
用占位符替换值:
INSERT INTO "table" (col1, col2, col3)
VALUES (unnest(?), unnest(?), unnest(?))
Run Code Online (Sandbox Code Playgroud)
您必须将数组或列表作为参数传递给此查询.这意味着你可以在不进行字符串连接的情况下进行大量的批量插入(以及它的所有谜题和危险:sql注入和引用地狱).
PostgreSQL已将FROM扩展添加到UPDATE.您可以这样使用它:
update "table"
set value = data_table.new_value
from
(select unnest(?) as key, unnest(?) as new_value) as data_table
where "table".key = data_table.key;
Run Code Online (Sandbox Code Playgroud)
该手册缺少一个很好的解释,但postgresql-admin邮件列表上有一个例子.我试着详细说明:
create table tmp
(
id serial not null primary key,
name text,
age integer
);
insert into tmp (name,age)
values ('keith', 43),('leslie', 40),('bexley', 19),('casey', 6);
update tmp set age = data_table.age
from
(select unnest(array['keith', 'leslie', 'bexley', 'casey']) as name,
unnest(array[44, 50, 10, 12]) as age) as data_table
where tmp.name = data_table.name;
Run Code Online (Sandbox Code Playgroud)
StackExchange 上还有其他 帖子UPDATE...FROM..使用VALUES子句而不是子查询来解释.它们可能更容易阅读,但仅限于固定数量的行.
atr*_*ain 14
我已经使用3种策略进行批量交易工作:
flush()针对Hibernate 的方法Session,而不是基础JDBC连接.它完成了与JDBC批处理相同的功能.顺便说一下,Hibernate还支持集合提取中的批处理策略.如果您使用@BatchSize,在获取关联时使用Hibernate来IN代替,则会=导致使用较少的SELECT语句来加载集合.
Ket*_*ema 12
批量插入可以这样做:
INSERT INTO "table" ( col1, col2, col3)
VALUES ( 1, 2, 3 ) , ( 3, 4, 5 ) , ( 6, 7, 8 );
Run Code Online (Sandbox Code Playgroud)
将插入3行.
SQL标准定义了多次更新,但PostgreSQL中没有实现.
引用:
"根据标准,列列表语法应该允许从单个行值表达式分配列的列表,例如子选择:
UPDATE帐户SET(contact_last_name,contact_first_name)=(SELECT last_name,first_name FROM salesmen WHERE salesmen.id = accounts.sales_id);"
参考:http://www.postgresql.org/docs/9.0/static/sql-update.html
将json填充到记录集中的速度非常快(PostgreSQL 9.3+)
big_list_of_tuples = [
(1, "123.45"),
...
(100000, "678.90"),
]
connection.execute("""
UPDATE mytable
SET myvalue = Q.myvalue
FROM (
SELECT (value->>0)::integer AS id, (value->>1)::decimal AS myvalue
FROM json_array_elements(%s)
) Q
WHERE mytable.id = Q.id
""",
[json.dumps(big_list_of_tuples)]
)
Run Code Online (Sandbox Code Playgroud)