为什么PostgreSQL比MongoDB还快?
发布时间:2020-12-13 17:15:47 所属栏目:百科 来源:网络整理
导读:PostgreSQL9.4带来了全新的NoSQL特性,并且根据EnterpriseDB的测试,其加载,插入和查询的性能都已经几倍于MongoDB了。 虽然我是PG的铁杆粉丝,但是关系数据库背负了ACID的重型装甲,在性能上居然能打败轻装上阵的NoSQL数据库总觉得有点离谱。 所以我在自己
PostgreSQL9.4带来了全新的NoSQL特性,并且根据EnterpriseDB的测试,其加载,插入和查询的性能都已经几倍于MongoDB了。
虽然我是PG的铁杆粉丝,但是关系数据库背负了ACID的重型装甲,在性能上居然能打败轻装上阵的NoSQL数据库总觉得有点离谱。 所以我在自己的环境里验证了一下EnterpriseDB的测试结果,并且小探一下PG取胜的原因。 1. EnterpriseDB的测试结果以下是EnterpriseDB的测试结果(数据量为5000万)http://www.enterprisedb.com/postgres-plus-edb-blog/marc-linster/postgres-outperforms-mongodb-and-ushers-new-developer-reality (还可以参考这篇译文:http://blog.jobbole.com/78215/) 2.我的验证结果 测试观点 为了使测试结果更加单纯,我准备单纯比拼CPU消耗(尽量排除IO和网络的干扰),设定以下测试条件。 1)所有数据都要放进内存 2)C/S都跑在同一台 单机上 所以,只在单机上进行10万条小数据量的测试。 注)EnterpriseDB的测试环境是32G内存的Amazon Web Services M3.2XLARGE实例,总数据量超过内存了。 测试环境 测试环境为个人PC上的VMware虚拟机 PC CPU:Intel Core i5-3470 3.2G(4核) MEM:6GB SSD:OCZ-VERTEX4 128GB(VMware虚拟机所在磁盘,非系统盘) OS:Win7 VMware虚拟机 CPU:4核 MEM:1GB OS:CentOS 6.5 PG:PostgreSQL 9.4.0(shared_buffers = 428MB,其他是默认值) MG: MongoDB 3.0.2 测试步骤 测试步骤非常简单,可以参考: https://github.com/EnterpriseDB/pg_nosql_benchmark 但是,在测试前,有些东西要改。 1)把数据量减小到10万 pg_nosql_benchmark-master/pg_nosql_benchmark: declare -a json_rows=(10000000) ==> declare -a json_rows=(100000) 2)修改 mongo的 一处 脚本(注) pg_nosql_benchmark-master/ lib/mongo_func_lib.sh: collectionsize="$(echo ${output}|awk -F"," '{print $5}'|cut -d":" -f2)" 6 }'|cut -d":" -f2)" 注 ) pg_nosql_benchmark原来是基于 2.6设计的,MongoDB3.0 的db.json_tables.stats()输出可能变了,所以这边要修改一下。 测试结果 点击(此处)折叠或打开
3. PostgreSQL真的比MongoDB还快吗
下面模仿
EnterpriseDB的测试方法,单独进行每一项测试。
3.1 测试数据修改测试脚本后再次执行,将加载和插入的数据文件保留下来。pg_nosql_benchmark: 点击(此处)折叠或打开 点击(此处)折叠或打开 查看一下数据 点击( 此处 )折叠或打开 查看 数据的总大小,10万条记录共 253MB。 3.2 PostgreSQL测试 1)清理旧数据 点击(此处)折叠或打开 2)加载数据 点击(此处)折叠或打开 执行测试期间的系统负载 点击(此处)折叠或打开 Cpu(s): 14.3%us,13.3%sy,0.0%ni,70.0%id,1.9%wa,0.1%hi,0.4%si,0.0%st Mem: 1019320k total,942632k used,76688k free,9768k buffers Swap: 2064376k total,80232k used,1984144k free,840444k cached PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 30622 postgres 20 0 588m 34m 32m R93.43.5 0:08.00 postgres 30619 postgres 20 0 98.6m 568 464 S 13.3 0.1 0:00.99 cat 17197 postgres 20 0 587m 212m 211m S 10.3 21.3 0:05.91 postgres 17199 postgres 20 0 586m 14m 13m S 5.0 1.4 0:03.26 postgres 30621 postgres 20 0 167m 2496 1984 S 3.3 0.2 0:00.30 psql 22 root 20 0 0 0 0 S 0.3 0.0 1:13.42 events/3 35 root 20 0 0 0 0 S 0.3 0.0 0:01.84 kblock 3) 建索引 4)查看存储空间大小 点击(此处)折叠或打开
5)数据查询 点击( 此处 )折叠或打开 -bash-4.1$ time psql-qAt benchmark-c"SELECT data FROM json_tables WHERE (data->>'brand') = 'ACME';">/dev/null
看看执行计划 点击(此处)折叠或打开 #explain(analyze,buffersSELECTdataFROMjson_tablesWHERE->'brand'='ACME';
居然是顺序扫描!GIN索引是吃干饭的吗? 仔细一看,原来 EnterpriseDB的测试SQL里把操作符写错了,无法使用GIN索引(想不到PG大牛出没的 EnterpriseDB也会犯这么低级的错误)。下面改下SQL让GIN上场。 点击(此处)折叠或打开 @'{"brand":"ACME"}'------------------------------------------------------------------------------------------------------------------------------
换到外面用psql测。 点击( 此处 )折叠或打开 "SELECT data FROM json_tables WHERE data @> '{"brand":"ACME"}'".326s
比以前有数据时快了1倍,但是没有explain (analyze,buffers)快。原因也很简单,输出结果太多了, 9091条数据在客户端和服务端都要消耗不少资源,而explain (analyze,buffers) 只是简单的在服务端把结果丢弃。 为了排除 处理大量结果数据的干扰,换一个0匹配的查询再试试。 点击( 此处 )折叠或打开 ":"ACME111.015s
再试试 0匹配的全表扫描。 点击(此处)折叠或打开 "set enable_bitmapscan=false;SELECT data FROM json_tables WHERE data @> '{"brand"}'"
6)数据插入 先清数据 点击(此处)折叠或打开 truncatejson_tables;
插入数据 点击(此处)折叠或打开 .1$ time-p psql-qAt benchmark--single-transaction -f sample_pg_inserts.json
插入期间的系统负载 点击(此处)折叠或打开 top - 09:58:31 up 1 day,12:58,load average: 0.23,0.05,0.02 Tasks: 161 total,3 running,0 zombie Cpu(s): 17.0%us,8.0%sy,71.7%id,3.0%wa,0.0%hi,0.3%si,936824k used,82496k free,11420k buffers Swap: 2064376k total,80128k used,1984248k free,833644k cached PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 2891 postgres 20 0 587m 110m 109m R74.511.1 0:07.45 postgres 2890 postgres 20 0 167m 2600 2044 R19.60.3 0:01.87 psql 17197 postgres 20 0 587m 212m 211m S 3.3 21.3 0:06.55 postgres 17199 postgres 20 0 586m 14m 13m S 3.0 1.4 0:03.54 postgres 17198 postgres 20 0 586m 2648 2512 S 0.3 0.3 0:01.09 postgres 25933 root 20 0 15036 1088 804 R 0.3 0.1 3:01.30 top 1 root 20 0 19356 816 648 S 0.0 0.1 0:01.18 init postgres进程的 CPU利用率为什么还要空这么多?原因也很简单,客户端和服务端是串行处理的,在空闲的时间里,它在等psql。 那么把postgres的psql进程的CPU利用率加起来就是94.1%,确实可以判断达到CPU性能瓶颈了。 等一等!其实这个测试中PG作弊了。 既然是和MongoDB PK普通的插入操作,应该是一个SQL一个事务才对。修改后再测。 点击(此处)折叠或打开 -f sample_pg_inserts.json
查看系统负载。 点击(此处)折叠或打开 top - 11:33:20 up 1 day,14:33,load average: 0.22,0.02 Tasks: 157 total,155 sleeping,0 zombie Cpu(s): 2.1%us,14.1%sy,10.2%wa,1.8%si,947744k used,71576k free,8044k buffers Swap: 2064376k total,67764k used,1996612k free,846260k cached PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 12577 postgres 20 0 587m 89m 88m D52.99.0 0:08.94 postgres 12576 postgres 20 0 167m 2596 2040 S 8.60.3 0:01.35 psql 12135 postgres 20 0 586m 48m 47m S 3.0 4.9 0:00.11 postgres 34 root 20 0 0 0 0 S 1.0 0.0 0:02.83 kblockd/0 36 root 20 0 0 0 0 S 0.3 0.0 0:02.63 kblockd/2 59 root 20 0 0 0 0 R 0.3 0.0 0:11.01 kswapd0 (由于这是单并发测试,不可避免会出现CPU空闲;但是在多并发的环境里,只要存储的吞吐和IOPS足够高,是完全可以把CPU撑满的。) 3.3MongoDB1)清理旧数据点击( 此处 )折叠或打开 >db.json_tables.drop)
2)加载数据 点击(此处)折叠或打开 -p mongoimport-typejson-collection json_tables-db benchmark<sample.jsonnull2null
加载期间的系统负载 点击(此处)折叠或打开 top - 10:15:50 up 1 day,13:15,load average: 0.16,0.01 Tasks: 152 total,1 running,151 sleeping,0 zombie Cpu(s): 17.4%us,18.7%sy,57.8%id,5.3%wa,0.2%hi,0.5%si,895156k used,124164k free,1532k buffers Swap: 2064376k total,65560k used,1998816k free,428380k cached PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 4673 postgres 20 0 694m 222m 3436 S89.822.4 0:05.53 mongoimport 4015 postgres 20 0 2771m 290m 142m S49.529.2 0:04.29 mongod (数据加载时,执行的单条语句,大量数据,所以 mongoimport 和mongod进程不是串行而是并行执行的关系) 3)建索引 点击(此处)折叠或打开 .1$echo"db.json_tables.ensureIndex( { "name": 1})"|time-p mongo benchmarknull
4)查看存储空间大小 .stats{
5)数据查询 点击( 此处 )折叠或打开 "DBQuery.shellBatchSize = 10000000000;db.json_tables.find({ brand: 'ACME'})"null
但是,不要急,看看资源占用。 点击(此处)折叠或打开 top - 10:55:46 up 1 day,13:55,load average: 0.13,0.04,150 sleeping,0 zombie Cpu(s): 24.7%us,0.4%sy,74.8%id,0.0%wa,0.1%si,935684k used,83636k free,1464k buffers Swap: 2064376k total,66976k used,1997400k free,615840k cached PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 8773 postgres 20 0 752m 67m 9052 R100.46.8 0:03.20 mongo 4015 postgres 20 0 2803m 830m 663m S 0.7 83.4 0:26.46 mongod 1424 root -2 0 85108 1448 1256 S 0.3 0.1 0:19.60 lrmd 1425 hacluste -2 0 89600 1496 1208 S 0.3 0.1 0:25.34 attrd 25911 root 20 0 98.0m 1104 972 S 0.3 0.1 0:40.12 sshd 1 root 20 0 19356 812 660 S 0.0 0.1 0:01.19 init 其实,执行psql时如果不加“-A”选项也会有类似的问题。 点击(此处)折叠或打开 -qt-p 5433 benchmarkreal0m2.124s
这说明什么?说明之前的查询测试结果根本就是误导嘛!(这就好比两个绝顶高手决斗的时候,比拼的却是谁的小弟递枪的速度快。) 为了排除大量数据处理的误导,下面执行一下0匹配的查询。 点击(此处)折叠或打开 "DBQuery.shellBatchSize = 10000000000;db.json_tables.find({ brand: 'ACME111'})"null
再试试0匹配的全表扫描。 点击(此处)折叠或打开 "db.json_tables.dropIndexes()"|mongo benchmark
6)数据插入 先清数据 点击(此处)折叠或打开 "db.json_tables.drop()"true
插入数据 点击(此处)折叠或打开 .1$ time mongo benchmark-quiet<sample_mongo_insertsnull
而且如果查看输出的话,还会发现一堆错误,这是由于MongoDB的控制台不允许插入大于4k的文档。 点击(此处)折叠或打开 下面看看插入时的系统负载 点击(此处)折叠或打开 top - 11:20:26 up 1 day,14:20,load average: 0.00,0.00,0.00 Tasks: 151 total,149 sleeping,0 zombie Cpu(s): 3.3%us,1.9%sy,71.1%id,4.9%wa,18.7%si,948452k used,70868k free,4076k buffers Swap: 2064376k total,68296k used,1996080k free,632796k cached PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 11269 postgres 20 0 753m 66m 9224 R89.66.7 0:15.23 mongo 4015 postgres 20 0 2803m 534m 371m S22.653.7 0:38.06 mongod 4. 总结
测试数据总结如下(并根据服务端进程CPU的消耗量进行性能对比):
PostgreSQL在NoSQL方面的表现确实抢眼。
PostgreSQL不仅是SQL+NoSQL+ACID的完美组合,性能还比
MongoDB技高一筹(分布式集群上MongoDB更有优势)。
*2)3个索引的总Size(MB) 这个结果和 EnterpriseDB的测试结果有很大出入。 1)数据加载 从服务端资源消耗的角度看,是 MongoDB的性能是 PostgreSQL的2倍。但是如果数据加载不能很好的并发展开,让mongoimport成为了瓶颈,那应该算打平。 另外, EnterpriseDB的 数据加载的测试结果和我的结果差异比较大,可能是因为EnterpriseDB的测试中,数据量超过了系统内存量,IO对测试结果的影响开始显现。 2)数据插入 从 服务端 资源消耗 的角度看,两者其实相差不大。EnterpriseDB的测试结果被mongo客户端的性能瓶颈绑架了。 3)数据查询 对无匹配数据(或少量匹配数据)的索引查询, PostgreSQL的性能是MongoDB的4倍(这一点也有点令人不解,同样是走索引的单点查询,为什么差距就这么大呢?)。 虽然EnterpriseDB的测试结果也表明PostgreSQL的性能是MongoDB 4倍左右,但EnterpriseDB的测试方法是有问题的。 4)数据大小 MongoDB的数据大小大约是 PostgreSQL的3倍,这和 EnterpriseDB的测试结果是一致的。 6. 参考http://www.enterprisedb.com/postgres-plus-edb-blog/marc-linster/edb-makes-open-call-postgres-nosql-performance-benchmarks http://blog.163.com/digoal@126/blog/static/16387704020151443228780/ http://blog.163.com/digoal@126/blog/static/16387704020151435825593/ http://blog.163.com/digoal@126/blog/static/1638770402015142858224/ http://www.cnblogs.com/lovecindywang/archive/2011/03/02/1969324.html(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |