![图片[1]-MySQL与PostgreSQL性能对比测试 包含吞吐量和延迟,读和写-主题铺](https://cdn.zhutipu.com/wp-content/uploads/2026/01/20260107103912942.png/ztp)
MySQL(海豚)和 PostgreSQL(大象)都是最好的、最广泛使用的开源数据库之一。它们经常从多个角度进行比较:支持的功能、SQL方言差异、架构和内部、资源利用率以及 – 性能。很多小伙伴接触到这两个数据库,不知道那个数据库比较好?主题铺看到一篇文章,转过来,分享一下MySQL与PostgreSQL性能:吞吐量和延迟,读和写的全面对比。
今天,我们将尽可能深入、广泛地研究性能 – 运行许多(17)个测试用例,并使用各种查询和工作负载,使用几张表来模拟现实世界中最常见场景,衡量吞吐量和延迟。然后让我们开始寻找答案:
哪个数据库,MySQL 或 PostgreSQL,性能更好?
配置
正如 我们所知 ,MySQL 和 PostgreSQL 在实现选择上有很大差异 ;为了捕捉这些差异,有几个表(PostgreSQL 定义):
CREATE TABLE "user" (
id BIGSERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
created_at TIMESTAMP NOT NULL,
updated_at TIMESTAMP
);
CREATE TABLE "order" (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL REFERENCES "user"(id) ON DELETE CASCADE,
created_at TIMESTAMP NOT NULL,
updated_at TIMESTAMP
);
CREATE INDEX order_user_id ON "order"(user_id);
CREATE TABLE "item" (
id BIGSERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL UNIQUE,
description TEXT,
price NUMERIC(10, 2) NOT NULL,
created_at TIMESTAMP NOT NULL,
updated_at TIMESTAMP
);
CREATE TABLE "order_item" (
id BIGSERIAL PRIMARY KEY,
order_id BIGINT NOT NULL REFERENCES "order"(id) ON DELETE CASCADE,
item_id BIGINT NOT NULL REFERENCES "item"(id) ON DELETE CASCADE
);
CREATE INDEX order_item_order_id ON "order_item"(order_id);
CREATE INDEX order_item_item_id ON "order_item"(item_id);
为了使结果可重复并更好地控制资源利用率,这两个数据库和测试都在 Docker 中运行。MySQL,版本 9.5,具有以下配置:
docker run -d -v "${volume_dir}:/var/lib/mysql" --network host \
-e "MYSQL_ROOT_PASSWORD=performance" \
-e "MYSQL_DATABASE=performance" \
--memory "16G" --cpus "8" --shm-size="1G" \
--name $container_name $container_name \
--innodb_buffer_pool_size=12G \
--innodb_redo_log_capacity=2G \
--transaction-isolation='READ-COMMITTED'
一些重要的自定义设置:
- 内存和 CPU – 分别限制在 16G 和 8 个;共享内存也从悲剧性的 64MB 默认值增加了
innodb_buffer_pool_size– 增加了用于数据索引缓存的总内存,以减少 I/O 并提高性能innodb_redo_log_capacity– 增加了重做日志文件占用的磁盘空间,以改善写入性能;某些写入操作发生的频率降低了- 读已提交事务隔离 – MySQL 的默认值是 可重复读 ;将其设置为与 PostgreSQL 默认值(读已提交)相同的(较低的)值可以使比较更公平,因为更高的隔离级别会引入额外的性能开销
PostgreSQL,版本 18.1,具有以下配置:
docker run -d -v "${volume_dir}:/var/lib/postgresql" --network host \
-e "POSTGRES_PASSWORD=performance" \
-e "POSTGRES_DB=performance" \
--memory "16G" --cpus "8" --shm-size="1G" \
--name $container_name $container_name \
-c shared_buffers=4GB \
-c work_mem=64MB \
-c effective_cache_size=12GB
同样,一些重要的调整:
shared_buffers– 与 MySQL 的innodb_buffer_pool_size非常相似;略小一些,因为 PostgreSQL 会大量使用操作系统的页缓存work_mem– 增加用于内部排序操作和哈希表的最大内存使用量(每个查询操作),这些内部用于某些连接和聚合effective_cache_size– 增加查询规划器用于估计可用于缓存数据的总内存量的参数
这些自定义化的目标不是拥有绝对最佳的配置,而是稍微优化数据库;充分利用其性能,而不是追求最后那几个百分点的性能。
然后,还有用于运行测试的 SqlDbPerformanceTests.java 测试程序——在两个数据库上执行各种测试并输出详细统计数据。为了简化管理,它也是构建在 Docker 中运行的(Java 25 & Maven)。通过简单的 run_test.py Python 脚本,可以更轻松地配置它并从多个可用的测试用例(17 个)中选择。
由于数据库有 8 个 CPU 可用 ,连接池大小为:8 * 16 = 128(MySQL)和 8 * 8 = 64(PostgreSQL)。实际测试表明,MySQL 受益于更多的连接,从而获得更好的性能;尤其是在写密集型工作负载中。
测试用例设计为运行几个回合 – 每秒执行 QUERIES_RATE 个,总共执行配置的 QUERIES_TO_EXECUTE 个。根据具体场景,这些数字从每秒几百个到几万个不等;大多数情况下为 QUERIES_TO_EXECUTE = 10 * QUERIES_RATE 。
要运行测试(本地),有几个脚本可以启动 Docker 中的 MySQL 和 PostgreSQL 实例,并在 Docker 中构建和运行 SqlDbPerformanceTests.java,选择测试用例和数据库。这一切都归结于执行:
# builds and runs MySQL in Docker
./build_and_run_mysql.bash
# builds and runs PostgreSQL in Docker
./build_and_run_postgresql.bash
# builds, without running just yet, performance tests in Docker
./build_performance_tests.bash
# runs performance tests in Docker, with the chosen test case & DB
./run_test.py
环境
所有测试将在我的本地计算机上运行:
- CPU – AMD Ryzen 7 PRO 7840U;8 个核心和 16 个线程,基础时钟速度为 3.3 GHz,最高加速至 5.1 GHz
- 内存 – 32 GiB
- 操作系统 – Ubuntu 24.04.3 LTS
磁盘(1 TB)详情:
sudo lshw -class disk -class storage
description: NVMe device
product: SAMSUNG MZVL21T0HDLU-00BLL
vendor: Samsung Electronics Co Ltd
bus info: pci@0000:03:00.0
version: 6L2QGXD7
width: 64 bits
clock: 33MHz
capabilities: nvme pm msi pciexpress msix nvm_express bus_master cap_list
configuration: driver=nvme latency=0 nqn=nqn.1994-11.com.samsung:nvme:PM9A1a:M.2:S75YNF0XC05149 state=live
resources: irq:68 memory:78c00000-78c03fff
如前所述,数据库在 Docker 中运行,内存限制为 16G,CPU 为 8 个。测试运行器没有任何限制。
结果
我们开始时,两个数据库都在 Docker 中运行,并且是空的——只有表架构被初始化。在结果中,我们将看到:
Total test duration: PT14.471S
Queries duration: PT10.619S
这些时间有时可能会有很大差异——这是因为对于某些测试用例,需要从数据库中获取现有数据以构建测试查询。这些额外查询的持续时间会从总测试持续时间中扣除: Queries duration = Total test duration - Additional queries duration 。否则,它们会扭曲结果,在不应计算时间的地方增加了时间。
正如所说,我们将运行大量案例,测试各种查询和工作负载。在执行 python3 run_test.py 时,以下选项可用:
- 插入用户
- 批量插入项目
- 批量插入订单
- 批量插入订单项
- SELECT USERS BY ID
- SELECT USERS BY EMAIL
- SELECT 排序按 ID 用户页面
- SELECT 订单 JOINED WITH 用户
- SELECT 订单 JOINED WITH 商品
- SELECT 用户 WITH 订单统计按 ID
- 根据 ID 更新用户邮箱
- 更新用户,通过 ID 更新 ATS
- 更新 ID 以多列方式更新用户
- 按 ID 删除订单
- 按 ID 批量删除订单
- 在事务中插入用户和订单及项目
- 按 ID 插入、更新、删除和选择用户
运行前 4 个插入选项后,每个数据库都将存储:
500 000用户500 000项目2 000 000个订单4 000 000个订单项关联
用于接下来的选择、更新、删除和混合测试用例。
插入
插入用户 – 插入 500 000 个用户,期望 10 000 QPS(每秒查询次数)的速率,逐个插入:
MySQL | PostgreSQL
Total test duration: PT1M54.078S | PT51.742S
Queries duration: PT1M54.078S | PT51.742S
Executed queries: 500000
Wanted queries rate: 10000/s
Actual queries rate: 4383/s | 9663/s
Min: 7.362 ms | 1.041 ms
Max: 150.018 ms | 40.748 ms
Mean: 26.801 ms | 2.191 ms
Percentile 50 (Median): 26.498 ms | 2.158 ms
Percentile 90: 31.082 ms | 2.658 ms
Percentile 99: 42.729 ms | 3.84 ms
Percentile 99.9: 114.339 ms | 13.304 ms
PostgreSQL 在这方面表现要好得多,而且我们可以清楚地看到——这个负载对 MySQL(海豚)来说已经太大了,而大象似乎仍然轻松呼吸,所以让我们用 30 000 QPS 重新运行它:
PostgreSQL
Total test duration: PT23.432S
Queries duration: PT23.432S
Executed queries: 500000
Wanted queries rate: 30000/s
Actual queries rate: 21338/s
Min: 1.159 ms
Max: 37.963 ms
Mean: 2.386 ms
Percentile 50 (Median): 2.367 ms
Percentile 90: 2.578 ms
Percentile 99: 4.009 ms
Percentile 99.9: 12.218 ms
21 338 次/秒的插入量,与 MySQL 的 仅 4383 次/秒相比 – Postgres 性能令人印象深刻,吞吐量赢了 4.87 倍!
批量插入项目 – 批量插入 500 000 项,每批 100 项,目标为 500 QPS:
MySQL | PostgreSQL
Total test duration: PT24.958S | PT23.651S
Queries duration: PT24.958S | PT23.651S
Executed queries: 5000
Wanted queries rate: 500/s
Actual queries rate: 200/s | 211/s
Min: 11.156 ms | 2.424 ms
Max: 232.688 ms | 36.817 ms
Mean: 26.504 ms | 4.1 ms
Percentile 50 (Median): 25.89 ms | 3.909 ms
Percentile 90: 35.57 ms | 5.113 ms
Percentile 99: 45.759 ms | 6.88 ms
Percentile 99.9: 183.714 ms | 30.237 ms
对于这两个数据库来说都稍微有点多;在吞吐量方面,差异并不大 – 200 QPS 对比 211 QPS,每个查询插入 100 项 。另一方面,Postgres 的延迟(查询持续时间)明显更低(更好)- 平均值 4.1 毫秒 对比 26.504 毫秒 ,99 分位数 6.88 毫秒 对比 45.759 毫秒 。
批量插入订单 – 批量插入 2 000 000 个订单,每批 100 个,目标为 2000 QPS:
MySQL | PostgreSQL
Total test duration: PT14.471S | PT11.004S
Queries duration: PT10.619S | PT6.759S
Executed queries: 20000
Wanted queries rate: 2000/s
Actual queries rate: 1883/s | 2959/s
Min: 12.355 ms | 2.026 ms
Max: 268.408 ms | 53.068 ms
Mean: 51.606 ms | 13.786 ms
Percentile 50 (Median): 45.796 ms | 13.701 ms
Percentile 90: 76.863 ms | 21.716 ms
Percentile 99: 146.497 ms | 38.114 ms
Percentile 99.9: 172.807 ms | 49.143 ms
大象明显超出了预期,在这里,无论是在吞吐量还是延迟方面,都优于海豚。让我们用 4000 QPS 重复一遍:
PostgreSQL
Total test duration: PT10.173S
Queries duration: PT5.658S
Executed queries: 20000
Wanted queries rate: 4000/s
Actual queries rate: 3535/s
Min: 2.487 ms
Max: 90.238 ms
Mean: 14.697 ms
Percentile 50 (Median): 13.997 ms
Percentile 90: 22.082 ms
Percentile 99: 34.779 ms
Percentile 99.9: 75.629 ms
因此,PostgreSQL 的 3535 次/秒插入 100 条记录 ,而 MySQL 的 1883 次/秒插入 。
批量插入订单项 – 通过将记录插入到 order_item 表中,将现有订单与现有项目关联起来。以 1000 为批次插入 4 000 000 行,实现所需的 400 QPS:
MySQL | PostgreSQL
Total test duration: PT41.329S | PT23.654S
Queries duration: PT7.365S | PT10.271S
Executed queries: 4000
Wanted queries rate: 400/s
Actual queries rate: 543/s | 389/s
Min: 25.842 ms | 32.322 ms
Max: 505.263 ms| 447.523 ms
Mean: 247.138 ms | 192.304 ms
Percentile 50 (Median): 221.993 ms | 188.728 ms
Percentile 90: 403.34 ms | 288.398 ms
Percentile 99: 482.361 ms | 394.913 ms
Percentile 99.9: 504.069 ms | 430.7 ms
令人惊讶的是,首条插入在吞吐量方面获胜的是海豚——543 QPS 对 389 QPS,性能提升 1.4 倍 。延迟实际上对大象来说更低(更好),所以总体而言,这基本上是平局。
总体来看插入操作,除了一个案例外,PostgreSQL 在吞吐量和延迟方面都占优。
选择
按 ID 选择用户 – 以所需的 50 000 QPS 速率按 ID 选择用户:
MySQL | PostgreSQL
Total test duration: PT16.428S | PT11.935S
Queries duration: PT14.939S | PT11.282S
Executed queries: 500000
Wanted queries rate: 50000/s
Actual queries rate: 33469/s | 44315/s
Min: 0.09 ms | 0.08 ms
Max: 100.489 ms | 101.967 ms
Mean: 1.579 ms | 0.523 ms
Percentile 50 (Median): 1.064 ms | 0.359 ms
Percentile 90: 2.665 ms | 0.921 ms
Percentile 99: 12.721 ms | 2.59 ms
Percentile 99.9: 25.143 ms | 14.47 m
大象似乎还有一些余力;使用 75 000 QPS 重新运行它:
PostgreSQL
Total test duration: PT11.264S
Queries duration: PT9.058S
Executed queries: 500000
Wanted queries rate: 75000/s
Actual queries rate: 55200/s
Min: 0.084 ms
Max: 102.201 ms
Mean: 0.874 ms
Percentile 50 (Median): 0.653 ms
Percentile 90: 1.348 ms
Percentile 99: 5.446 ms
Percentile 99.9: 18.749 m
PostgreSQL 击败了 MySQL;优势在单次插入上不如明显,但仍然很大 – 55,200 QPS 对比 33,469 QPS;平均值为 0.874 毫秒 对比 1.579 毫秒 ,以及 5.446 毫秒 对比 12.721 毫秒 在 99 分位数上。
按邮箱查询用户 – 通过邮箱( 辅助索引 )读取用户,目标为 50 000 QPS:
MySQL | PostgreSQL
Total test duration: PT17.139S | PT12.047S
Queries duration: PT15.631S | PT11.280S
Executed queries: 500000
Wanted queries rate: 50000/s
Actual queries rate: 31988/s | 44324/s
Min: 0.106 ms | 0.086 ms
Max: 99.775 ms | 59.287 ms
Mean: 1.772 ms | 0.612 ms
Percentile 50 (Median): 1.234 ms | 0.447 ms
Percentile 90: 2.985 ms | 1.088 ms
Percentile 99: 12.865 ms | 2.812 ms
Percentile 99.9: 26.701 ms | 11.028 ms
大象已经获胜,但仍能轻松呼吸——让我们同样以 75 000 QPS 的目标再次运行此案例:
PostgreSQL
Total test duration: PT10.862S
Queries duration: PT9.348S
Executed queries: 500000
Wanted queries rate: 75000/s
Actual queries rate: 53487/s
Min: 0.084 ms
Max: 82.551 ms
Mean: 0.834 ms
Percentile 50 (Median): 0.618 ms
Percentile 90: 1.288 ms
Percentile 99: 5.358 ms
Percentile 99.9: 16.843 ms
对 PostgreSQL 来说更是大胜 – 53,487 QPS 对比 31,988 QPS;延迟也更低。
按 ID 排序选择用户页面 – 目标为 5000 QPS,按 ID 升序选择用户;结果限制为从 10 到 100 的随机数,偏移量也是随机的,范围在 0 到 10 000 之间:
MySQL | PostgreSQL
Total test duration: PT10.968S | PT10.537S
Queries duration: PT10.968S | T10.537S
Executed queries: 50000
Wanted queries rate: 5000/s
Actual queries rate: 4559/s | 4745/s
Min: 0.139 ms | 0.118 ms
Max: 71.472 ms | 51.453 ms
Mean: 3.118 ms | 1.556 ms
Percentile 50 (Median): 1.561 ms | 1.117 ms
Percentile 90: 6.297 ms | 2.362 ms
Percentile 99: 41.294 ms | 9.146 ms
Percentile 99.9: 55.248 ms | 42.884 m
有趣的是,在吞吐量方面,DBs 非常接近的第一个 select 案例是 4559 QPS 对比 4745 QPS。但总体而言,Postgres 仍然占据优势。
现在,我们将介绍一些连接操作。
选择与用户连接的订单 – 以想要的 35 000 QPS 速率读取订单 ID,并将它们与用户通过 o.user_id = u.id 进行连接。订单和用户之间存在多对一的关系:
MySQL | PostgreSQL
Total test duration: PT14S | PT13.154S
Queries duration: PT11.977S | PT12.414S
Executed queries: 350000
Wanted queries rate: 35000/s
Actual queries rate: 29223/s | 28194/s
Min: 0.105 ms | 0.152 ms
Max: 99.931 ms | 54.302 ms
Mean: 1.739 ms | 1.897 ms
Percentile 50 (Median): 1.177 ms | 1.321 ms
Percentile 90: 2.923 ms | 2.85 ms
Percentile 99: 14.543 ms | 19.823 ms
Percentile 99.9: 27.36 ms | 26.859 ms
最后,MySQL 击败了 Postgres,尽管只是略微 – 29 223 QPS 对比 28 194 QPS;延迟也大多是较低的。
SELECT ORDERS JOINED WITH ITEMS – 以每秒 30,000 个查询(30 000 QPS)的速率按 id 读取订单,首先通过 order_item.order_id 将订单与订单项进行连接,然后通过 order_item.item_id 将订单项与商品进行连接。订单与订单项之间存在多对多的关系;订单项与商品之间也存在相同类型的关系。此案例测试了双方都具有多对多关系的双重连接。
MySQL | PostgreSQL
Total test duration: PT14.859S | PT15.566S
Queries duration: PT13.263S | PT14.843S
Executed queries: 300000
Wanted queries rate: 30000/s
Actual queries rate: 22619/s | 20211/s
Min: 0.155 ms | 0.199 ms
Max: 77.021 ms | 80.307 ms
Mean: 2.824 ms | 2.799 ms
Percentile 50 (Median): 1.962 ms | 1.866 ms
Percentile 75: 3.219 ms | 2.748 ms
Percentile 90: 5.091 ms | 4.093 ms
Percentile 99: 19.795 ms | 28.604 ms
Percentile 99.9: 29.203 ms | 34.309 ms
Dolphin 再次获胜!它似乎确实在连接方面表现更好;吞吐量 比之前提高了 1.12 倍 – 22,619 QPS 对比 20,211 QPS,而延迟则表现不一;部分情况有所改善 – 更高的百分位数,部分情况则有所恶化 – 更低的百分位数和平均值。
按 ID 选择具有订单统计的用户 – 通过 id 选择用户,将其与订单进行 u.id = o.user_id (一对多) 的连接,并为每个用户计算各种统计数据:COUNT(*) AS orders、 MIN(o.created_at) AS oldest_order_created_at 和 MAX(o.created_at) AS latest_order_created_at 。目标速率是 40 000 QPS:
MySQL | PostgreSQL
Total test duration: PT18.485S | PT13.101S
Queries duration: PT17.505S | PT12.621S
Executed queries: 400000
Wanted queries rate: 40000/s
Actual queries rate: 22851/s | 31693/s
Min: 0.151 ms | 0.138 ms
Max: 106.217 ms | 113.18 ms
Mean: 2.759 ms | 1.648 ms
Percentile 50 (Median): 1.77 ms | 1.137 ms
Percentile 90: 5.092 ms | 2.622 ms
Percentile 99: 19.511 ms | 15.651 ms
Percentile 99.9: 34.338 ms | 23.988 ms
出乎意料的是,在最后一个连接案例中,大象具有优势——31,693 QPS 对比 22,851 QPS,性能提升 1.39 倍;延迟也更低。
总结选择查询:
- Postgres 在单表单行选择上表现优异
- 对于单表多行排序选择,两个数据库的性能非常接近
- MySQL 在连接方面略有优势
- 使用聚合函数的查询对 Elephant 来说性能更优
更新
通过 ID 更新用户邮箱 – 通过 id 更新用户邮箱(索引列),以期望的 5000 QPS 的速率:
MySQL | PostgreSQL
Total test duration: PT13.612S | PT10.245S
Queries duration: PT13.29S | PT10.108S
Executed queries: 50000
Wanted queries rate: 5000/s
Actual queries rate: 3762/s | 4946/s
Min: 6.71 ms | 1.101 ms
Max: 61.503 ms | 16.098 ms
Mean: 26.337 ms | 2.506 ms
Percentile 50 (Median): 26.457 ms | 2.423 ms
Percentile 90: 31.342 ms | 2.947 ms
Percentile 99: 36.415 ms | 9.243 ms
Percentile 99.9: 42.76 ms | 13.755 ms
对于 MySQL 已经太过于多了一——它峰值仅为 3762 QPS,未能达到 5000 QPS。大象似乎远低于其极限运行;让我们以 4 倍更高的速率重新运行此案例——20 000 QPS:
PostgreSQL
Total test duration: PT11.608S
Queries duration: PT11.057S
Executed queries: 200000
Wanted queries rate: 20000/s
Actual queries rate: 18088/s
Min: 1.141 ms
Max: 17.132 ms
Mean: 2.483 ms
Percentile 50 (Median): 2.458 ms
Percentile 90: 2.897 ms
Percentile 99: 4.827 ms
Percentile 99.9: 10.896 ms
好吧,海豚在这里完全落后——3762 QPS 对比 18 088 QPS,差了 4.8 倍 ,与大象相比;延迟也更高。
UPDATE USER UPDATED ATS BY ID – 通过 ID 修改用户更新时间戳(未索引列),期望的速率 5000 QPS:
MySQL | PostgreSQL
Total test duration: PT11.653S | PT10.239S
Queries duration: PT11.344S | PT9.947S
Executed queries: 50000
Wanted queries rate: 5000/s
Actual queries rate: 4408/s | 5026/s
Min: 0.128 ms | 1.089 ms
Max: 114.719 ms | 12.321 ms
Mean: 15.172 ms | 2.351 ms
Percentile 50 (Median): 17.715 ms | 2.368 ms
Percentile 90: 33.223 ms | 2.891 ms
Percentile 99: 37.726 ms | 3.588 ms
Percentile 99.9: 110.402 ms | 8.559 ms
如前所述,大象(Elephant)再次表现出色,尽管优势不那么明显。但再次运行它,使用 20 000 QPS:
PostgreSQL
Total test duration: PT11.588S
Queries duration: PT10.802S
Executed queries: 200000
Wanted queries rate: 20000/s
Actual queries rate: 18515/s
Min: 1.115 ms
Max: 16.476 ms
Mean: 2.524 ms
Percentile 50 (Median): 2.52 ms
Percentile 90: 2.966 ms
Percentile 99: 4.977 ms
Percentile 99.9: 11.745 ms
与邮件更新相比,海豚在这里完全处于劣势 – 4408 QPS 对比 18 515 QPS,差了 4.2 倍 ;延迟也更高。
最后,关于更新操作,我们有 通过 ID 更新用户多个列 – 通过 ID 更改用户的电子邮件(索引)和更新时间(非索引);同样地,对于 5000 QPS 的目标:
MySQL | PostgreSQL
Total test duration: PT13.722S | PT10.228S
Queries duration: PT13.345S | PT9.989S
Executed queries: 50000
Wanted queries rate: 5000/s
Actual queries rate: 3747/s | 5005/s
Min: 6.812 ms | 1.114 ms
Max: 117.566 ms | 14.903 ms
Mean: 26.284 ms | 2.387 ms
Percentile 50 (Median): 26.161 ms | 2.394 ms
Percentile 90: 31.188 ms | 2.906 ms
Percentile 99: 39.774 ms | 4.108 ms
Percentile 99.9: 113.642 ms | 9.15 m
PostgreSQL 再次优于 MySQL。既然大象似乎对这种负载不再感到印象深刻,这里提供的是 20 000 QPS 版本:
PostgreSQL
Total test duration: PT11.665S
Queries duration: PT11.083S
Executed queries: 200000
Wanted queries rate: 20000/s
Actual queries rate: 18046/s
Min: 1.088 ms
Max: 16.465 ms
Mean: 2.507 ms
Percentile 50 (Median): 2.463 ms
Percentile 90: 2.947 ms
Percentile 99: 4.704 ms
Percentile 99.9: 10.178 ms
18,046 QPS 对比 3,747 QPS – Postgres 占据优势 4.82 倍。
对于更新操作,象形符号在所有情况下都更优越。
删除操作
按 ID 删除订单 – 以所需的 10 000 QPS 速率删除订单。重要的是,订单与 order_item 表相关联(多对多);删除一个订单会级联到相关的订单项:
MySQL | PostgreSQL
Total test duration: PT19.589S | PT10.776S
Queries duration: PT17.871S | PT10.35S
Executed queries: 100000
Wanted queries rate: 10000/s
Actual queries rate: 5596/s | 9662/s
Min: 0.139 | 0.085 ms
Max: 119.909 ms | 16.123 ms
Mean: 20.563 ms | 1.953 ms
Percentile 50 (Median): 22.36 ms | 2.191 ms
Percentile 90: 31.335 ms | 2.628 ms
Percentile 99: 43.039 ms | 4.334 ms
Percentile 99.9: 114.248 ms | 13.747 ms
在更新操作方面,PostgreSQL 获胜,并且仍有提升空间;再次运行以 20 000 QPS 为目标的案例:
PostgreSQL
Total test duration: PT11.408S
Queries duration: PT10.938S
Executed queries: 200000
Wanted queries rate: 20000/s
Actual queries rate: 18285/s
Min: 0.084 ms
Max: 18.622 ms
Mean: 2.009 ms
Percentile 50 (Median): 2.285 ms
Percentile 90: 2.917 ms
Percentile 99: 4.661 ms
Percentile 99.9: 13.522 ms
18,285 QPS 与 5,596 QPS 的吞吐量对比,性能提升 3.27 倍;延迟也更低。
按 ID 批量删除订单 – 按批量删除订单,每批 100 个,目标 1000 QPS。如前所述,重要的是要记住订单与 order_item 表相关联;删除订单会级联到相关的订单项:
MySQL | PostgreSQL
Total test duration: PT32.555S | PT10.135S
Queries duration: PT16.125S | PT7.445S
Executed queries: 10000
Wanted queries rate: 1000/s
Actual queries rate: 620/s | 1343/s
Min: 16.219 ms | 1.572 ms
Max: 925.516 ms | 117.852 ms
Mean: 181.728 ms | 11.387 ms
Percentile 50 (Median): 144.041 ms | 4.975 ms
Percentile 90: 372.383 ms | 29.104 ms
Percentile 99: 670.586 ms | 60.834 ms
Percentile 99.9: 846.825 ms | 89.203 ms
为 PostgreSQL 提供更多展示其优势的空间,使用 20 000 QPS:
PostgreSQL
Total test duration: PT11.184S
Queries duration: PT6.943S
Executed queries: 20000
Wanted queries rate: 2000/s
Actual queries rate: 2881/s
Min: 1.868 ms
Max: 143.329 ms
Mean: 16.547 ms
Percentile 50 (Median): 12.604 ms
Percentile 90: 34.174 ms
Percentile 99: 66.48 ms
Percentile 99.9: 102.943 ms
为大象带来了又一次完胜 – 2881 QPS 对比 620 QPS,性能提升 4.65 倍 。
在更新操作方面,PostgreSQL 在删除操作上总体表现更优。
事务
在事务中插入用户、订单和订单项 – 在单个事务中插入一个用户和一个包含两个项目的订单。这需要 4 条插入语句:1 条用于 user 表,1 条用于 order 表,以及 2 条用于 order_item 表。目标是在每秒执行 2500 此类事务,这相当于 4 * 2500 = 10 000 QPS:
MySQL | PostgreSQL
Total test duration: PT11.921S | PT10.104S
Queries duration: PT10.522S | PT9.742S
Executed queries: 25000
Wanted queries rate: 2500/s
Actual queries rate: 2376/s | 2566/s
Min: 10.33 ms | 1.289 ms
Max: 118.617 ms | 16.185 ms
Mean: 26.841 ms | 2.821 ms
Percentile 50 (Median): 25.505 ms | 2.672 ms
Percentile 90: 35.535 ms | 3.483 ms
Percentile 99: 62.132 ms | 6.525 ms
Percentile 99.9: 111.082 ms | 10.12 m
由于单次插入对海豚来说存在问题,因此大象在这里获胜并不令人意外:2566 QPS 对比 2376 QPS,延迟也更低。既然它们似乎还有余力,让我们用 4 * 5000 = 20 000 QPS 对 MySQL 进行测试,用 4 * 10 000 = 40 000 QPS 对 PostgreSQL 进行测试:
MySQL | PostgreSQL
Total test duration: PT14.473S | PT6.337S
Queries duration: PT13.62S | PT5.671S
Executed queries: 50000
Wanted queries rate: 5000/s | 10000/s
Actual queries rate: 3671/s | 8816/s
Min: 8.475 ms | 1.35 ms
Max: 128.404 ms | 27.007 ms
Mean: 29.103 ms | 3.587 ms
Percentile 50 (Median): 28.566 ms | 2.891 ms
Percentile 90: 36.64 ms | 6.126 ms
Percentile 99: 53.419 ms | 11.209 ms
Percentile 99.9: 122.303 ms | 18.949 m
差一点了!象能够处理 8816 TPS(每秒事务数),相当于 4 * 8816 = 35 264 QPS;海豚的最高值达到 3671 TPS,相当于 4 * 3671 = 14 684 QPS – PostgreSQL 的吞吐量高出 2.4 倍 。
大象能够处理更多的事务,并且以更低的延迟完成。
插入、更新、删除和选择
按 ID 插入、更新、删除和选择用户 – 按 ID 插入、更新、删除和选择用户,读:写比例为 1:1。也就是说,对于每 3 次按 ID 选择用户,就有 1 次用户插入、1 次按 ID 用户更新和 1 次用户删除。它测试混合负载,同时读取和写入;期望的速率是 7500 QPS:
MySQL | PostgreSQL
Total test duration: PT12.313S | PT10.299S
Queries duration: PT11.905S | PT10.116S
Executed queries: 75000
insert-users: 12425 | 12349
update-user-emails-by-id: 12343 | 12481
delete-users-by-id: 12582 | 12399
select-users-by-id: 37650 | 37771
Wanted queries rate: 7500/s
Actual queries rate: 6300/s | 7413/s
Min: 0.092 ms | 0.081 ms
Max: 87.487 ms | 26.09 ms
Mean: 12.813 ms | 1.154 ms
Percentile 50 (Median): 1.174 ms | 0.369 ms
Percentile 90: 30.671 ms | 2.545 ms
Percentile 99: 40.635 ms | 3.068 ms
Percentile 99.9: 63.811 ms | 9.014 ms
PostgreSQL 以更高的吞吐量和更低的延迟获胜,但这远非最终结论。再次运行案例,使用 25 000 QPS:
PostgreSQL
Total test duration: PT11.506S
Queries duration: PT10.665S
Executed queries: 250000
insert-users: 41775
update-user-emails-by-id: 42164
delete-users-by-id: 41420
select-users-by-id: 124641
Wanted queries rate: 25000/s
Actual queries rate: 23441/s
Min: 0.087 ms
Max: 19.568 ms
Mean: 1.372 ms
Percentile 50 (Median): 0.997 ms
Percentile 90: 2.805 ms
Percentile 99: 4.634 ms
Percentile 99.9: 11.616 ms
因此,象群能够处理这个负载的 23,441 QPS,而海豚只能处理 6,300 QPS。 这意味着在混合工作负载方面,Postgres 的优势是 3.72 倍 。
摘要
PostgreSQL(大象),在几乎所有场景中都优于 MySQL(海豚 ):在总共执行的 17 个测试用例中,PostgreSQL 赢了 14 个,有 1 个平局。使用 每秒查询数(QPS) 来衡量吞吐量(越高越好), 平均值和 99 分位数 来衡量延迟(越低越好),以下是 PostgreSQL 表现更优的高层次总结:
- 插入
- 1.05 – 4.87倍更高的吞吐量
- 延迟降低3.51 – 11.23倍(平均值)和4.21 – 10.66倍(99分位数)
- PostgreSQL 在单行插入方面提供
21 338 QPS with 4.009 ms at the 99th percentile,而与 MySQL 的 4,383 QPS & 42.729 ms 相比;对于100 行的批量插入,它实现3535 QPS with 34.779 ms at the 99th percentile,而与 MySQL 的 1,883 QPS & 146.497 ms 相比
- 选择
- 1.04 – 1.67 倍更高的吞吐量
- 平均延迟降低 1.67 – 2 倍,99 百分位延迟降低 1.25 – 4.51 倍
- PostgreSQL 通过 id 进行单行查询时,性能为
55 200 QPS with 5.446 ms at the 99th percentile,而 MySQL 的性能为 33,469 QPS & 12.721 ms;对于多行排序查询,PostgreSQL 的性能为4745 QPS with 9.146 ms at the 99th percentile,而 MySQL 的性能为 4,559 QPS & 41.294 ms。
- 更新
- 4.2 – 4.82倍更高的吞吐量
- 平均延迟降低6.01 – 10.6倍,99分位数延迟降低7.54 – 8.46倍
- Postgres 通过多列的 ID 更新,而 MySQL 为 3747 QPS & 39.774 ms
- 删除
- 3.27 – 4.65倍更高的吞吐量
- 平均延迟降低10.24倍 – 10.98倍,99分位数延迟降低9.23倍 – 10.09倍
- Postgres 通过 id 删除操作
18 285 QPS with 4.661 ms at the 99th percentile,而 MySQL 为 5596 QPS & 43.039 ms
- 插入、更新、删除和查询混合操作
- 3.72倍更高的吞吐量
- 平均降低了9.34倍,99分位数降低了8.77倍的低延迟
- Postgres 在这个 1:1 写入:读取比例的混合负载下交付
23 441 QPS with 4.634 ms at the 99th percentile,与 MySQL 的 6300 QPS & 40.635 ms 相比
这里是对所有测试用例的更详细总结:
- 插入 – 用户表的单行数据
- MySQL –
4383 QPS; 平均值:26.801 ms,99 百分位数:42.729 ms - Postgres –
21 338 QPS; 平均值:2.386 ms,99 百分位数:4.009 ms - Postgres 以 4.87 倍的吞吐量优势获胜,平均延迟低 11.23 倍,99 百分位数低 10.66 倍
- MySQL –
- 插入 – 批量插入100行商品表数据
- MySQL –
200 QPS; 平均值:26.504 毫秒,99 分位数:45.759 毫秒 - Postgres –
211 QPS; 平均值:4.1 毫秒,99 分位数:6.88 毫秒 - Postgres 在吞吐量上领先 1.05 倍,平均延迟低 6.46 倍,99 分位数延迟低 6.65 倍
- MySQL –
- 插入 – 100 行订单表的批量插入
- MySQL –
1883 QPS; 平均值:51.606 ms,99 百分位数:146.497 ms - Postgres –
3535 QPS; 平均值 14.697 ms,99 百分位数:34.779 ms - Postgres 以 1.88 倍的吞吐量优势获胜,平均延迟低 3.51 倍,99 百分位数低 4.21 倍
- MySQL –
- 插入 – 1000 行 order_item 表数据
- MySQL –
543 QPS; 平均值:247.138 毫秒,99 百分位数:482.361 毫秒 - Postgres –
389 QPS; 平均值:192.304 毫秒,99 百分位数:394.913 毫秒 - MySQL 在吞吐量上获胜,高 1.4 倍,但在延迟上处于劣势,平均值低 1.29 倍,99 百分位数低 1.22 倍,因此 Postgres 获胜 – 因此结果是平局
- MySQL –
- 选择 – 按用户 ID
- MySQL –
33 469 QPS; 平均值:1.579 ms,99 百分位:12.721 ms - Postgres –
55 200 QPS; 平均值:0.874 ms,99 百分位:5.446 ms - PostgreSQL 以 1.65 倍更高的吞吐量获胜,平均延迟降低了 1.8 倍,99 分位数延迟降低了 2.34 倍。
- MySQL –
- 选择 – 通过电子邮件选择用户
- MySQL –
31 988 QPS; 平均值:1.772 ms,99 百分位:12.865 ms - PostgreSQL –
53 487 QPS;平均:0.834 毫秒,99 百分位:5.358 毫秒 - PostgreSQL 以 1.67 倍更高的吞吐量获胜,平均延迟降低 2.12 倍,99 百分位延迟降低 2.4 倍
- MySQL –
- 选择 – 按用户 ID 页面排序,大小为 10 到 100
- MySQL –
4559 QPS;平均:3.118 毫秒,99 百分位:41.294 毫秒 - PostgreSQL –
4745 QPS;平均:1.556 毫秒。99 百分位:9.146 毫秒 - PostgreSQL 以 1.04 倍更高的吞吐量获胜,平均延迟降低 2 倍,99 分位数延迟降低 4.51 倍。
- MySQL –
- 选择 – 按 id 排序,与多对一用户关联
- MySQL –
29 223 QPS; 平均值:1.739 ms,99 百分位:14.543 ms - Postgres –
28 194 QPS; 平均值:1.897 ms,99 百分位数:19.823 ms - MySQL 在吞吐量上胜出,比 Postgres 高出 1.04 倍,平均延迟低 1.09 倍,99 百分位数低 1.36 倍
- MySQL –
- 选择 – 按 id 排序,与多对多关系 order_item 连接,与多对多关系 item 连接
- MySQL –
22 619 QPS; 平均值:2.824 ms,99 百分位数:19.795 ms - Postgres –
20 211 QPS; 平均值:2.799 ms,99 百分位数:28.604 ms - MySQL 在吞吐量上领先 1.12 倍,延迟在平均值上高 1.01 倍(略差),在 99 百分位数上低 1.45 倍
- MySQL –
- 选择 – 通过 id 查询用户,与一对多订单连接,并计算一些聚合函数
- MySQL –
22 851 QPS; 平均值:2.759 ms,99 百分位数:19.511 ms - Postgres –
31 693 QPS; 平均值:1.648 ms,99 百分位数:15.651 ms - Postgres 以 1.39 倍更高的吞吐量获胜,平均延迟低 1.67 倍,99 百分位数低 1.25 倍
- MySQL –
- 更新 – 通过索引的电子邮件列的 ID 来更新用户
- MySQL –
3762 QPS; 平均值:26.337 ms,99 百分位数:36.415 ms - Postgres –
18 088 QPS;平均:2.483 毫秒,99 百分位:4.827 毫秒 - PostgreSQL 以 4.8 倍更高的吞吐量获胜,平均延迟低 10.6 倍,99 分位数延迟低 7.54 倍
- MySQL –
- 更新 – 基于未索引的 updated_at 列的用户 ID
- MySQL –
4408 QPS;平均:15.172 毫秒,99 分位数:37.726 毫秒 - PostgreSQL –
18 515 QPS;平均:2.524 毫秒,99 分位数:4.977 毫秒 - PostgreSQL 以 4.2 倍更高的吞吐量获胜,平均延迟降低 6.01 倍,99 百分位延迟降低 7.58 倍
- MySQL –
- 更新 – 通过多个列的 ID 更新用户
- MySQL –
3747 QPS;平均:26.284 毫秒,99 百分位:39.774 毫秒 - PostgreSQL –
18 046 QPS;平均:2.507 毫秒,99 百分位:4.704 毫秒 - PostgreSQL 以 4.82 倍更高的吞吐量获胜,平均延迟降低 10.48 倍,99 分位数延迟降低 8.46 倍
- MySQL –
- 删除 – 按 id 排序
- MySQL –
5596 QPS; 平均值:20.563 ms,99 百分位:43.039 ms - Postgres –
18 285 QPS;平均:2.009 ms,99 百分位:4.661 ms - Postgres 在吞吐量上领先 3.27 倍,平均延迟低 10.24 倍,99 百分位低 9.23 倍
- MySQL –
- 删除操作 – 按 id 批量删除 100 行
- MySQL –
620 QPS;平均:181.728 ms,99 百分位:670.586 ms - Postgres –
2881 QPS;平均:16.547 ms,99 百分位:66.48 ms - Postgres 在吞吐量上以 4.65 倍的优势获胜,平均延迟低 10.98 倍,99 百分位低 10.09 倍
- MySQL –
- 事务 – 一个用户的插入,一个订单和两个订单项
- MySQL –
3671 QPS;平均:29.103 ms,99 百分位:53.419 ms - Postgres –
8816 QPS; 平均值:3.587 ms,99 百分位数:11.209 ms - Postgres 以 2.4 倍更高的吞吐量获胜,平均延迟低 8.11 倍,99 百分位数低 4.77 倍
- MySQL –
- 插入、更新、删除和选择 – 按用户 id 混合,在 1:1 写读比例中
- MySQL –
6300 QPS; 平均值:12.813 ms,99 百分位:40.635 ms - Postgres –
23 441 QPS;平均:1.372 毫秒,99 百分位数:4.634 毫秒 - Postgres 在吞吐量上领先 3.72 倍,平均延迟低 9.34 倍,99 百分位数低 8.77 倍
- MySQL –
原文链接:https://binaryigor.com/mysql-vs-postgresql-performance.html

















暂无评论内容