大事务和并发的性能?

Ale*_*ans 7 postgresql concurrency postgresql-9.3

如果我有一个数百万行的表,并且运行一个更新 50k 行的事务,那么这会对性能产生什么影响?

假设它的索引正确,应该不会花很长时间,但是哪些行被锁定以及该表的使用如何受到影响?

  1. 在事务开始后和完成之前是否可以读取事务期间更新的行?
  2. 在事务开始后和完成之前是否可以读取事务期间未更新的行?
  3. 如果另一个事务开始尝试更改先前未完成的事务正在更改的行,那么该事务会在开始时失败还是在尝试提交之后失败(假设发生冲突)?

我的问题是针对 Postgres 9.3 的;我认为存在差异。

taf*_*fer 9

在事务开始后和完成之前是否可以读取事务期间更新的行?

\n\n

是的,在 Postgres 中,读取不会阻止写入,写入也不会阻止读取。Postgres文档指出:

\n\n
\n

在内部,通过使用多版本模型(多版本并发控制,MVCC)来维护数据一致性。这意味着在查询数据库时,每个事务都会看到一段时间之前的数据快照(数据库版本),而不管底层数据的当前状态如何。[\xe2\x80\xa6] 使用并发控制的 MVCC 模型而不是锁定的主要优点是,在 MVCC 中,为查询(读取)数据而获取的锁不会与为写入数据而获取的锁发生冲突,所以读永远不会阻止写,写也永远不会阻止读。

\n
\n\n

在事务开始后和完成之前是否可以读取事务期间未更新的行?

\n\n

是的。

\n\n

如果另一个事务开始尝试更改先前未完成的事务正在更改的行,那么该事务会在开始时失败还是在尝试提交之后失败(假设发生冲突)?

\n\n

这取决于事务隔离级别以及您是否发出依赖于读取或盲写的写入。使用默认级别“已提交读”,第二个事务必须等待第一个事务完成写入。在较高的事务级别中,其中一个事务可能会因序列化错误而中止。

\n\n

psql您实际上可以通过运行两个会话来亲自尝试:

\n\n

第一节:

\n\n
-- first set up a table\nCREATE TABLE tools (id SERIAL PRIMARY KEY, description STRING);\nINSERT INTO tools(description) VALUES(\'scredriver\');\nINSERT INTO tools(description) VALUES(\'hammer\');\n\n-- now type the following into two psql sessions\n          SESSION 1             |          SESSION 2\n                                |\nBEGIN TRANSACTION;              |\nUPDATE tools                    |\n   SET description = \'anvil\'    |\n WHERE id = 1;                  |\n                                | BEGIN TRANSACTION;\n                                |UPDATE tools\n                                |   SET description = \'wrench\'\n                                | WHERE id = 1;\n                                |-- this transaction is blocked\n                                |-- until the other transaction\nCOMMIT TRANSACTION;             |-- commits\n
Run Code Online (Sandbox Code Playgroud)\n\n

正如您将看到的,会话 2 将被会话 1 阻止。只有会话 1 提交,会话 2 才能继续。

\n\n

postgres 文档还包含有关如何在使用更高事务级别时避免阻塞和序列化失败的性能建议。

\n