Performance PostgreSQL如何比SQLite更快地执行写操作?
我做了一个简单的整数更新性能测试。SQLite每秒仅更新15次,而PostgreSQL每秒更新1500次 SQLite案例的数字似乎是 SQLite站点中的解释似乎是旋转磁盘的一个基本限制 实际上,SQLite可以轻松地在每个数据库中执行50000条或更多INSERT语句 在普通台式电脑上排名第二。但它只能做几十件事 每秒事务数。事务处理速度受 磁盘驱动器的旋转速度。交易通常需要 磁盘盘片的两次完整旋转,在7200RPM的磁盘上 驱动器限制您每秒处理大约60个事务。交易 速度受磁盘驱动器速度限制,因为(默认情况下)SQLite 实际上,等待数据真正安全地存储在磁盘上 在事务完成之前显示。那样的话,如果你突然 断电或操作系统崩溃时,数据仍然安全。对于 详细信息,请阅读SQLite中的原子提交 默认情况下,每个INSERT语句都是它自己的事务。但是如果你 用BEGIN…COMMIT环绕多个INSERT语句,然后使用所有 插入被分组到单个事务中。需要的时间 提交事务在所有随附的插入中摊销 语句,因此每个insert语句的时间大大减少 另一个选项是运行PRAGMA synchronous=OFF。此命令将 使SQLite不等待数据到达磁盘表面,这将 使写操作看起来快得多。但是如果你失去了权力 在事务的中间,您的数据库文件可能损坏。 这是真的吗?那么,PostgreSQL如何能比SQLite执行得更快呢? (我在PostgreSQL中将Performance PostgreSQL如何比SQLite更快地执行写操作?,performance,sqlite,postgresql,clojure,Performance,Sqlite,Postgresql,Clojure,我做了一个简单的整数更新性能测试。SQLite每秒仅更新15次,而PostgreSQL每秒更新1500次 SQLite案例的数字似乎是 SQLite站点中的解释似乎是旋转磁盘的一个基本限制 实际上,SQLite可以轻松地在每个数据库中执行50000条或更多INSERT语句 在普通台式电脑上排名第二。但它只能做几十件事 每秒事务数。事务处理速度受 磁盘驱动器的旋转速度。交易通常需要 磁盘盘片的两次完整旋转,在7200RPM的磁盘上 驱动器限制您每秒处理大约60个事务。交易 速度受磁盘驱动器速度限制
fsync
和synchronous\u commit
选项设置为on
)
更新:
以下是用Clojure编写的完整测试代码:
(defproject foo "0.1.0-SNAPSHOT"
:repositories {"sonatype-oss-public" "https://oss.sonatype.org/content/groups/public/"}
:dependencies [[org.clojure/clojure "1.5.1"]
[org.clojure/java.jdbc "0.3.0-SNAPSHOT"]
[com.mchange/c3p0 "0.9.2.1"]
[org.xerial/sqlite-jdbc "3.7.2"]
[postgresql "9.1-901.jdbc4"]])
输出为:
; Running "select * from foo" 20000 times in SQLite
"Elapsed time: 1802.426963 ms (11,096 ops)"
"Elapsed time: 1731.118831 ms (11,553 ops)"
"Elapsed time: 1749.842658 ms (11,429 ops)"
; Running "update foo set bar=bar+1 where id=1" 100 times in SQLite
"Elapsed time: 6362.829057 ms (15 ops)"
"Elapsed time: 6405.25075 ms (15 ops)"
"Elapsed time: 6352.943553 ms (15 ops)"
; Running "select * from foo" 20000 times in PostgreSQL
"Elapsed time: 2898.636079 ms (6,899 ops)"
"Elapsed time: 2824.77372 ms (7,080 ops)"
"Elapsed time: 2837.622659 ms (7,048 ops)"
; Running "update foo set bar=bar+1 where id=1" 5000 times in PostgreSQL
"Elapsed time: 3213.120219 ms (1,556 ops)"
"Elapsed time: 3564.249492 ms (1,402 ops)"
"Elapsed time: 3280.128708 ms (1,524 ops)"
pg_fsync_测试结果:
C:\temp>"C:\Program Files\PostgreSQL\9.3\bin\pg_test_fsync"
5 seconds per test
O_DIRECT supported on this platform for open_datasync and open_sync.
Compare file sync methods using one 8kB write:
(in wal_sync_method preference order, except fdatasync
is Linux's default)
open_datasync 81199.920 ops/sec 12 usecs/op
fdatasync n/a
fsync 45.337 ops/sec 22057 usecs/op
fsync_writethrough 46.470 ops/sec 21519 usecs/op
open_sync n/a
Compare file sync methods using two 8kB writes:
(in wal_sync_method preference order, except fdatasync
is Linux's default)
open_datasync 41093.981 ops/sec 24 usecs/op
fdatasync n/a
fsync 38.569 ops/sec 25927 usecs/op
fsync_writethrough 36.970 ops/sec 27049 usecs/op
open_sync n/a
Compare open_sync with different write sizes:
(This is designed to compare the cost of writing 16kB
in different write open_sync sizes.)
1 * 16kB open_sync write n/a
2 * 8kB open_sync writes n/a
4 * 4kB open_sync writes n/a
8 * 2kB open_sync writes n/a
16 * 1kB open_sync writes n/a
Test if fsync on non-write file descriptor is honored:
(If the times are similar, fsync() can sync data written
on a different descriptor.)
write, fsync, close 45.564 ops/sec 21947 usecs/op
write, close, fsync 33.373 ops/sec 29964 usecs/op
Non-Sync'ed 8kB writes:
write 889.800 ops/sec 1124 usecs/op
假设您使用的是普通硬盘(即没有ssd),则每秒最多可写入50-100次。似乎每秒15次写入的速度稍低,但并非不可能
因此,如果Postgres每秒进行1500次更新,它们要么被写入某个缓冲区/缓存,要么被压缩为一次更新。在不了解更多实际测试的情况下,很难说哪一个是真正的原因,但如果您要打开一个事务,更新一行1500次,然后提交,那么Postgres应该足够聪明,只执行一次对磁盘的“真正”写入。这取决于它们如何实现快照隔离 SQLite使用文件锁定作为隔离事务的一种手段,只允许在完成所有读取后才命中写入 相比之下,Postgres使用了一种更复杂的方法,称为多币种版本控制(mvcc),它允许多个写入与多个读取并行进行
丹尼斯的答案包含了你需要的所有链接。我会选择一个不太详细但可能更容易理解的答案 Sqlite不使用任何复杂的事务管理器,其中没有隐藏的高级多任务逻辑。它执行你让它执行的东西,完全按照这个顺序。换句话说:它完全按照你告诉它的去做。如果您尝试从两个进程中使用相同的数据库,您将遇到问题 另一方面,PostgreSQL是一个非常复杂的数据库:它有效地支持多个并发读写。把它想象成一个异步系统——你只安排要完成的工作,实际上你并不控制它的细节——Postgres为你做这件事
如何提高您的效率?在一个事务中加入几个-几十个-数百个更新/插入。对于一个简单的表,您将获得非常好的性能。您的怀疑是正确的。具有您指定的设置的PostgreSQL不应能够以每秒1500次的单独顺序事务对旋转介质执行任何更新 您的IO堆栈中可能存在关于如何实现同步的谎言或错误。这意味着您的数据在意外断电或操作系统故障后有严重损坏的风险
从pg_test_fsync的结果来看,情况确实如此。open_datasync是Windows下的默认值,它的速度似乎不现实,因此肯定不安全。当我在Windows7机器上运行pg_test_fsync时,我看到了同样的情况。实际上,旋转磁盘上的任何写入都是10毫秒量级的(典型数字是8毫秒) 这意味着,如果您在磁盘中写入相同的位置,则每秒写入的次数略多于100次,这对于数据库来说是一种非常奇怪的情况。请参阅ACM中的“您不知道jack关于磁盘的情况”,通常一个磁盘可以在一次循环中安排10次读写
因此,一个数据库每秒可以执行1000次写入,甚至更多。10年前,我在台式计算机上看到过每秒执行1500个事务的应用程序。这与写入(提交)磁盘的速度(或延迟)无关。它是关于有序写入的。您使用PosgreSQL在每个事务中进行了多少次更新?一个简单的整数更新性能测试:好的,所以我们不知道您实际做了什么。@CL。我没有显式使用事务,所以它是每个事务一次更新。我知道我可以在一个事务中包装多个更新以提高速度,但这不是我现在要问的问题。@DanielVérité这是一个包含两个整数列的表,查询为
update foo set bar=bar+1,其中id=1
我相信它实际上与事务隔离相关的问题有关。@Denis:非常正确,最重要的是,只有在提交之后才能保证何时所有内容都必须写入磁盘。同时,它取决于事务隔离级别。阅读
C:\temp>"C:\Program Files\PostgreSQL\9.3\bin\pg_test_fsync"
5 seconds per test
O_DIRECT supported on this platform for open_datasync and open_sync.
Compare file sync methods using one 8kB write:
(in wal_sync_method preference order, except fdatasync
is Linux's default)
open_datasync 81199.920 ops/sec 12 usecs/op
fdatasync n/a
fsync 45.337 ops/sec 22057 usecs/op
fsync_writethrough 46.470 ops/sec 21519 usecs/op
open_sync n/a
Compare file sync methods using two 8kB writes:
(in wal_sync_method preference order, except fdatasync
is Linux's default)
open_datasync 41093.981 ops/sec 24 usecs/op
fdatasync n/a
fsync 38.569 ops/sec 25927 usecs/op
fsync_writethrough 36.970 ops/sec 27049 usecs/op
open_sync n/a
Compare open_sync with different write sizes:
(This is designed to compare the cost of writing 16kB
in different write open_sync sizes.)
1 * 16kB open_sync write n/a
2 * 8kB open_sync writes n/a
4 * 4kB open_sync writes n/a
8 * 2kB open_sync writes n/a
16 * 1kB open_sync writes n/a
Test if fsync on non-write file descriptor is honored:
(If the times are similar, fsync() can sync data written
on a different descriptor.)
write, fsync, close 45.564 ops/sec 21947 usecs/op
write, close, fsync 33.373 ops/sec 29964 usecs/op
Non-Sync'ed 8kB writes:
write 889.800 ops/sec 1124 usecs/op