【发布时间】:2013-10-08 17:50:42
【问题描述】:
我做了一个简单的整数更新性能测试。 SQLite 每秒只更新 15 次,而 PostgreSQL 每秒更新 1500 次。
SQLite 大小写的数字似乎是normal。
SQLite 站点中的 FAQ 解释为好像它是旋转磁盘的基本限制。
实际上,SQLite 可以轻松地执行 50,000 或更多的 INSERT 语句 在普通台式计算机上排名第二。但它只会做几十 每秒事务数。交易速度受限于 磁盘驱动器的转速。交易通常需要 磁盘盘片的两个完整旋转,在 7200RPM 磁盘上 drive 将您限制为每秒大约 60 个事务。交易 速度受磁盘驱动器速度的限制,因为(默认情况下)SQLite 实际上一直等到数据真正安全地存储在磁盘上 在交易完成之前浮出水面。这样,如果你突然 断电或如果您的操作系统崩溃,您的数据仍然是安全的。为了 详细信息,请阅读 SQLite 中的原子提交。
默认情况下,每个 INSERT 语句都是它自己的事务。但是如果你 用 BEGIN...COMMIT 包围多个 INSERT 语句,然后所有 插入被分组到一个事务中。需要的时间 提交事务在所有封闭的插入中摊销 语句,因此每个插入语句的时间大大减少。
另一个选项是运行 PRAGMA synchronous=OFF。该命令将 导致 SQLite 不等待数据到达磁盘表面,这将 使写操作看起来要快得多。但如果你失去力量 在事务处理过程中,您的数据库文件可能会损坏。
这个描述是真的吗?那么,PostgreSQL 怎么能比 SQLite 执行得这么快呢?
(我在 PostgreSQL 中将 fsync 和 synchronous_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"]])
(ns foo.core
(:require [clojure.java.jdbc :as jdbc]
[clojure.java.jdbc.ddl :as ddl])
(:import [com.mchange.v2.c3p0 ComboPooledDataSource]))
(def sqlite
(let [spec {:classname "org.sqlite.JDBC"
:subprotocol "sqlite"
:subname "test.db"}]
{:datasource (doto (ComboPooledDataSource.)
(.setDriverClass (:classname spec))
(.setJdbcUrl (str "jdbc:" (:subprotocol spec) ":" (:subname spec)))
(.setMaxIdleTimeExcessConnections (* 30 60))
(.setMaxIdleTime (* 3 60 60)))}))
(def postgres
(let [spec {:classname "org.postgresql.Driver"
:subprotocol "postgresql"
:subname "//localhost:5432/testdb"
:user "postgres"
:password "uiop"}]
{:datasource (doto (ComboPooledDataSource.)
(.setDriverClass (:classname spec))
(.setJdbcUrl (str "jdbc:" (:subprotocol spec) ":" (:subname spec)))
(.setUser (:user spec))
(.setPassword (:password spec))
(.setMaxIdleTimeExcessConnections (* 30 60))
(.setMaxIdleTime (* 3 60 60)))}))
(doseq [x [sqlite postgres]]
(jdbc/db-do-commands x
(ddl/create-table :foo [:id :int "PRIMARY KEY"] [:bar :int])))
(doseq [x [sqlite postgres]]
(jdbc/insert! x :foo {:id 1 :bar 1}))
(defmacro bench
[expr n]
`(dotimes [_# 3]
(let [start# (. System (nanoTime))]
(dotimes [_# ~n]
~expr)
(let [end# (. System (nanoTime))
elapsed# (/ (double (- end# start#)) 1000000.0)
operation-per-sec# (long (/ (double ~n) (/ (double (- end# start#)) 1000000000)))]
(prn (str "Elapsed time: " elapsed# " ms (" (format "%,d" operation-per-sec#) " ops)"))))))
(bench (jdbc/query sqlite ["select * from foo"]) 20000)
(bench (jdbc/execute! sqlite ["update foo set bar=bar+1 where id=?" 1]) 100)
(bench (jdbc/query postgres ["select * from foo"]) 20000)
(bench (jdbc/execute! postgres ["update foo set bar=bar+1 where id=?" 1]) 5000)
输出是:
; 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_test 结果:
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
【问题讨论】:
-
这与写入(提交)到磁盘的速度(或延迟)无关。这是关于有序写入
-
您使用 PosgreSQL 对每个事务进行了多少更新?
-
一个简单的整数更新性能测试:好的,所以我们不知道你实际做了什么。
-
@CL。我没有明确使用事务,所以它是每个事务的一个更新。我知道我可以在一个事务中包含多个更新以提高速度,但这不是我现在要问的。
-
@DanielVérité 这是一个有 2 个整数列的表,查询为
update foo set bar=bar+1 where id=1
标签: performance sqlite postgresql clojure