一直好奇于MongoDB的读写速度以及它的特有的NoSQL查询机制。有幸作了一次Sybase ASA(SQLAnywhere12)和MongoDB写入数据行的速度的比较。
这对于大规模Web访问来说,非常重要。
比较基准:
写入100000行,每行三列,id(整数), name varchar(32), col_blob或clob,8K左右长度。比较最终的写入时间。
1. ASA12:
dbinit.exe bench.db
dbeng12.exe bench.db
代码如下:
package com.sql9;
import java.sql.*;
import java.util.Properties;
public class Bench4SQLAnywhere
{
// prepare about 100000 rows of data
// (id, name, col_clob)
// e.g. (1, 'wang', 'abcdef12345555555555555555555555555555555555555555555....')
// the col_blob should be 8K or longer.
// dsn: benchASA
public static final String DSN = "bench_ASA";
public static final String url = "jdbc:sqlanywhere:UserID=dba;Password=sql;Server=bench;DBN=bench";
public static void testWrite()
{
Connection conn = null;
System.out.println("begin time: " + new Timestamp(new java.util.Date().getTime()));
// System.setProperty("java.library.path", "v:/target/ASA120/Bin32");
try
{
Properties props = new Properties();
props.put("DYNAMIC_PREPARE", true);
conn = DriverManager.getConnection("jdbc:sqlanywhere:DSN=" + DSN + ";uid=dba;pwd=sql", props);
// conn = DriverManager.getConnection(url, props);
Statement stmt = conn.createStatement();
stmt.executeUpdate("create table t(id int primary key, name varchar(32) null, col_blob long varchar null)");
stmt.close();
stmt = null;
PreparedStatement pstmt = conn.prepareStatement("insert into t values(?, ?, ?)");
StringBuilder sb = new StringBuilder(8000);
for (int i=0; i<800; i++)
{
sb.append("abcde12345");
}
for (int i=0; i<100000; i++)
{
pstmt.setInt(1, i+1);
pstmt.setString(2, "wang " + i);
pstmt.setString(3, sb.toString());
pstmt.executeUpdate();
if ((i+1) % 1000 == 0)
{
conn.commit();
}
}
conn.commit();
pstmt.close();
}
catch (Exception ex)
{
ex.printStackTrace();
}
finally
{
// if conn not null, just drop the table ????
}
System.out.println("end time: " + new Timestamp(new java.util.Date().getTime()));
try
{
if (conn != null)
{
Statement stmt = conn.createStatement();
stmt.executeUpdate("drop table t");
stmt.close();
}
}
catch (Exception ex)
{
ex.printStackTrace();
}
finally
{
if (conn != null)
{
try
{
conn.close();
}
catch (Exception ex2) {}
}
}
}
/**
* @param args
*/
public static void main(String[] args)
{
// TODO Auto-generated method stub
testWrite();
}
/**
* result
* begin time: 2012-04-12 17:44:22.292
end time: 2012-04-12 17:55:16.971
*/
}
我们可以看到最终结果: begin time: 2012-04-12 17:44:22.292 end time: 2012-04-12 17:55:16.971, 大概花了11分钟。是够慢的。运行时需要指定-Djava.library.path=<asa12>/bin32目录。2. MongoDB:
启动:mongod.exe --dbpath E:\xionghe\MongoDB\mongodb\data
客户端简单命令:
db.testCollection.count()
代码如下:
package com.sql9;
import java.net.UnknownHostException;
import java.sql.Timestamp;
import java.util.HashMap;
import com.mongodb.Mongo;
import com.mongodb.DB;
import com.mongodb.DBCollection;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import com.mongodb.DBCursor;
import com.mongodb.MongoException;
public class Bench4MongoDB
{
public static void testWrite() throws UnknownHostException, MongoException
{
Mongo m = new Mongo();
// or
// Mongo m = new Mongo( "localhost" );
// or
// Mongo m = new Mongo( "localhost" , 27017 );
System.out.println("begin time: " + new Timestamp(new java.util.Date().getTime()));
DB db = m.getDB( "test" );
StringBuilder sb = new StringBuilder(8000);
for (int i=0; i<800; i++)
{
sb.append("abcde12345");
}
// on row looks like
DBCollection col = db.getCollection("testCollection");
for (int i=0; i<100000; i++)
{
// pstmt.setInt(1, i+1);
// pstmt.setString(2, "wang " + i);
// pstmt.setString(3, sb.toString());
// pstmt.executeUpdate();
// if ((i+1) % 1000 == 0)
// {
// conn.commit();
// }
BasicDBObject doc = new BasicDBObject();
doc.put("id", i);
doc.put("name", "wang " + i);
doc.put("col_blob", sb.toString());
// col.insert(doc);
col.save(doc);
}
System.out.println("end time: " + new Timestamp(new java.util.Date().getTime()));
// finally remove the col1 from the mongoDB.
// col.remove(new BasicDBObject(new HashMap()));
}
/**
* @param args
*/
public static void main(String[] args)
{
// TODO Auto-generated method stub
try
{
testWrite();
}
catch (UnknownHostException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (MongoException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
begin time: 2012-04-12 18:11:18.99
end time: 2012-04-12 18:11:44.412
*/
}
看看所花时间:begin time: 2012-04-12 18:11:18.99end time: 2012-04-12 18:11:44.412只花了: 26秒左右。我只能说差距太明显了。。。。。。。
再看看生成的文件大小:bench.db: 814,900KB, .log: 819328KB.mongodb的testdb: test.* (test.0, ... test.5)共6个文件1,073,479,685B也就1G左右。
分析:
ASA之所以慢如此之多,一是它基于关系表,有一个BLOB/CLOB字段要跨页存储,同时它要维护主键的索引。MongoDB则没有维护索引。可能对
testCollection创建一个索引,再进行比较更合理一些,但我有理由相信,即算加上索引,MongoDB也比ASA要快很多。
看来,MongoDB适用于互联网所言非虚。
不过,我再看了下MongoDB的license:
是一个开放源码项目,其数据库基于 GNU AGPL (Affero General Public License) version 3.0 的许可。此许可是 GNU GPL 的一个修正版,它弥补了版权限制不适用于软件使用而仅适用软件分发的漏洞。这对于在云中存储而不经常安装在客户端设备上的软件当然是重要的。使用常规 GPL ,您会感觉到实际上无法进行分发,因此潜在地规避了许可条款。
AGPL 只适用于它自己的数据库应用程序,不适用于 MongoDB 的其他组成部分。允许开发人员从各种编程语言连接 MongoDB 的官方驱动程序在 Apache License Version 2.0 许可下分发。 MongoDB 文档的使用基于 Creative Commons 许可。
这是否意味着,如果我要开发一款基于Cloud的大型互联网应用,可以直接使用MongoDB和自己的产品集成,而没有任何法律风险?
有熟悉此道的朋友,请告诉我。。。