MySQL版本:5.1.50,驱动版本:5.1.6(最新的5.1.13有很多杂七杂八的问题)
MongoDB版本:1.6.2,驱动版本:2.1
操作系统:Windows XP SP3(这个影响应该不大)
CPU:Intel Core2 E6550 2.33G
内存:2G(足够了)
MySQL启动参数:bin\mysqld --no-defaults --console --character-set-server=utf8 --max_connections=1000 --max_user_connections=1000
MongoDB启动参数:bin\mongod --dbpath data\ --directoryperdb --rest --maxConns 1000 –quiet
除了加大最大连接数之外,均使用默认参数
该测试主要为改进当前系统的日志的存储和查询性能提供参考,所以表的创建也以实际情况为例,下面是MySQL的建表语句:
CREATE TABLE `flt_evecurrent` ( `NodeID` int(11) NOT NULL DEFAULT '0', `FltID` int(11) NOT NULL DEFAULT '0', `ObjID` int(11) DEFAULT NULL, `StationID` int(11) DEFAULT NULL, `EveType` int(11) DEFAULT NULL, `Severity` int(11) DEFAULT NULL, `ReportTime` date DEFAULT NULL, `CreateTime` date DEFAULT NULL, `EveContent` varchar(1024) DEFAULT NULL, `EveDesc` varchar(256) DEFAULT NULL, PRIMARY KEY (`NodeID`,`FltID`) ); |
MongoDB类似,索引按照查询语句的查询字段创建,该例子中为ObjID和CreateTime两个字段创建索引。
分别插入100万条记录,并对其做100个用户并发查询操作。
MySQL每一次都Drop表,MongoDB每一次都删除data目录。
查询的时候,从第二次查询开始,连续记录三次。
|
插入时间 |
查询时间 |
MySQL InnoDB引擎 无索引 |
10分33秒 |
39.516秒、35.907秒、39.907秒 |
MySQL InnoDB引擎 有索引 |
11分16秒 |
非常不稳定:22.531秒、13.078秒、23.078秒、26.047秒、21.234秒、28.469秒、20.922秒、13.328秒 |
MySQL MyISAM引擎 无索引 |
3分21秒 |
22.812秒、23.343秒、23.125秒 |
MySQL MyISAM引擎 有索引 |
3分50秒 |
10.312秒、10.359秒、10.296秒 |
MongoDB无索引 |
37秒 |
59.531秒、60.063秒、59.891秒 |
MongoDB有索引 |
50秒 |
3.484秒、3.453秒、3.453秒 |
磁盘空间占用(有索引时候的占用,无索引情况差不多):
MySQL MyISAM:57MB
MySQL InnoDB:264MB
MongoDB:464MB
另外测试中还发现一个有意思的现象,如果MongoDB查询中,如果单独查询ObjID字段,耗时约1秒,如果单独查询CreateTime字段,耗时约10秒,如果两个字段合起来查,就是上面的结果,约3秒,估计MongoDB内部对查询顺序作了优化吧。
该测试没有对MySQL和MongoDB的启动参数作任何优化,因为根据经验即便优化性能也不会有数量级的提升,另外也只是给一个大概的印象吧,第一印象总是很重要的,呵呵。
下面是代码:
MySQL插入
import java.sql.Connection;import java.sql.DriverManager;import java.sql.Statement;import java.util.Random;public class AddData { public static void main(String[] args) throws Exception { Connection connection; Statement statement; Class.forName("com.mysql.jdbc.Driver"); connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", ""); statement = connection.createStatement(); // 清理表 statement.executeUpdate("truncate table flt_evecurrent"); // 增加记录 Random random = new Random(System.currentTimeMillis()); for (int fltId = 0; fltId < 1000000; fltId++) { if ((fltId % 10000) == 0) { System.out.println(fltId); } int nodeId = 0; int objId = random.nextInt(100); int stationId = objId; int eveType = 0; int severity = 0; String reportTime = String.format("2010-09-%d", fltId / 100000 + 1); String createTime = reportTime; String eveContent = "ContentContentContent"; String eveDesc = "DescDescDesc"; String sql = String.format("insert into flt_evecurrent (NodeID, FltID, ObjID, StationID, EveType, Severity, ReportTime, CreateTime, EveContent, EveDesc) " + "values (%d, %d, %d, %d, %d, %d, '%s', '%s', '%s', '%s')", nodeId, fltId, objId, stationId, eveType, severity, reportTime, createTime, eveContent, eveDesc); statement.executeUpdate(sql); } statement.close(); connection.close(); }}
MySQL查询
import java.sql.Connection;import java.sql.DriverManager;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;import java.util.ArrayList;import java.util.List;import java.util.logging.Level;import java.util.logging.Logger;import org.junit.AfterClass;import org.junit.BeforeClass;import org.junit.Test;public class PerfTest { public PerfTest() { } @BeforeClass public static void setUpClass() throws Exception { } @AfterClass public static void tearDownClass() throws Exception { } @Test public void test() throws Exception { Class.forName("com.mysql.jdbc.Driver");// final Connection connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", ""); ListMongoDB插入threads = new ArrayList (); for (int i = 0; i < 100; i++) { Thread thread = new Thread(new Runnable() { public void run() { Connection connection = null; Statement statement = null; ResultSet resultSet = null; try { connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", ""); statement = connection.createStatement(); System.out.println(String.format("线程%d查询开始", Thread.currentThread().getId())); resultSet = statement.executeQuery("select count(*) from flt_evecurrent where objid in (30,50,70) and createtime between '2010-09-03' and '2010-09-07'"); resultSet.first(); System.out.println(String.format("数量:%d", resultSet.getLong("count(*)"))); System.out.println(String.format("线程%d查询结束", Thread.currentThread().getId())); } catch (Exception ex) { Logger.getLogger(PerfTest.class.getName()).log(Level.SEVERE, null, ex); } finally { try { connection.close(); } catch (SQLException ex) { Logger.getLogger(PerfTest.class.getName()).log(Level.SEVERE, null, ex); } } } }); thread.start(); threads.add(thread); } for (Thread thread : threads) { thread.join(); }// connection.close(); }}
import com.mongodb.BasicDBObject;import com.mongodb.DB;import com.mongodb.DBCollection;import com.mongodb.Mongo;import java.util.Calendar;import java.util.Date;import java.util.Random;public class AddData { public static void main(String[] args) throws Exception { Mongo mongo = new Mongo("localhost", 27017); DB db = mongo.getDB("test"); DBCollection coll = db.getCollection("flt_evecurrent"); // 删除表 coll.drop(); // 增加索引 coll.createIndex(new BasicDBObject("ObjID", 1)); coll.createIndex(new BasicDBObject("CreateTime", 1)); // 增加记录 Random random = new Random(System.currentTimeMillis()); Calendar calendar = Calendar.getInstance(); for (int fltId = 0; fltId < 1000000; fltId++) { if ((fltId % 10000) == 0) { System.out.println(fltId); } int nodeId = 0; int objId = random.nextInt(100); int stationId = objId; int eveType = 0; int severity = 0; calendar.set(2010, 9, fltId / 100000 + 1); Date reportTime = calendar.getTime(); Date createTime = reportTime; String eveContent = "ContentContentContent"; String eveDesc = "DescDescDesc"; BasicDBObject obj = new BasicDBObject(); obj.put("NodeID", nodeId); obj.put("FltID", fltId); obj.put("ObjID", objId); obj.put("StationID", stationId); obj.put("EveType", eveType); obj.put("Severity", severity); obj.put("ReportTime", reportTime); obj.put("CreateTime", createTime); obj.put("EveContent", eveContent); obj.put("EveDesc", eveDesc); coll.insert(obj); } }}
MongoDB查询
import com.mongodb.BasicDBObject;import com.mongodb.DB;import com.mongodb.DBCollection;import com.mongodb.Mongo;import java.util.ArrayList;import java.util.Calendar;import java.util.Date;import java.util.List;import org.junit.AfterClass;import org.junit.BeforeClass;import org.junit.Test;public class PerfTest { public PerfTest() { } @BeforeClass public static void setUpClass() throws Exception { } @AfterClass public static void tearDownClass() throws Exception { } @Test public void test() throws Exception { // 增大Mongo驱动的并发连接数量 System.setProperty("MONGO.POOLSIZE", "1000"); Mongo mongo = new Mongo("localhost", 27017); DB db = mongo.getDB("test"); final DBCollection coll = db.getCollection("flt_evecurrent"); Calendar calendar = Calendar.getInstance(); calendar.set(2010, 9, 3); Date beginTime = calendar.getTime(); calendar.set(2010, 9, 7); Date endTime = calendar.getTime(); List objIds = new ArrayList(); objIds.add(30); objIds.add(50); objIds.add(70); final BasicDBObject query = new BasicDBObject(); query.put("CreateTime", new BasicDBObject("$gte", beginTime).append("$lte", endTime)); query.put("ObjID", new BasicDBObject("$in", objIds)); Listthreads = new ArrayList (); for (int i = 0; i < 100; i++) { Thread thread = new Thread(new Runnable() { public void run() { System.out.println(String.format("线程%d查询开始", Thread.currentThread().getId())); long count = coll.getCount(query); System.out.println(String.format("数量:%d", count)); System.out.println(String.format("线程%d查询结束", Thread.currentThread().getId())); } }); thread.start(); threads.add(thread); } for (Thread thread : threads) { thread.join(); } }}
MySQL的建表语句
-- MyISAM无索引DROP TABLE `flt_evecurrent`;CREATE TABLE `flt_evecurrent` ( `NodeID` int(11) NOT NULL DEFAULT '0', `FltID` int(11) NOT NULL DEFAULT '0', `ObjID` int(11) DEFAULT NULL, `StationID` int(11) DEFAULT NULL, `EveType` int(11) DEFAULT NULL, `Severity` int(11) DEFAULT NULL, `ReportTime` date DEFAULT NULL, `CreateTime` date DEFAULT NULL, `EveContent` varchar(1024) DEFAULT NULL, `EveDesc` varchar(256) DEFAULT NULL, PRIMARY KEY (`NodeID`,`FltID`)) ENGINE=MyISAM DEFAULT CHARSET=utf8;-- MyISAM有索引DROP TABLE `flt_evecurrent`;CREATE TABLE `flt_evecurrent` ( `NodeID` int(11) NOT NULL DEFAULT '0', `FltID` int(11) NOT NULL DEFAULT '0', `ObjID` int(11) DEFAULT NULL, `StationID` int(11) DEFAULT NULL, `EveType` int(11) DEFAULT NULL, `Severity` int(11) DEFAULT NULL, `ReportTime` date DEFAULT NULL, `CreateTime` date DEFAULT NULL, `EveContent` varchar(1024) DEFAULT NULL, `EveDesc` varchar(256) DEFAULT NULL, PRIMARY KEY (`NodeID`,`FltID`), KEY `ObjID` (`ObjID`), KEY `CreateTime` (`CreateTime`)) ENGINE=MyISAM DEFAULT CHARSET=utf8;-- InnoDB无索引DROP TABLE `flt_evecurrent`;CREATE TABLE `flt_evecurrent` ( `NodeID` int(11) NOT NULL DEFAULT '0', `FltID` int(11) NOT NULL DEFAULT '0', `ObjID` int(11) DEFAULT NULL, `StationID` int(11) DEFAULT NULL, `EveType` int(11) DEFAULT NULL, `Severity` int(11) DEFAULT NULL, `ReportTime` date DEFAULT NULL, `CreateTime` date DEFAULT NULL, `EveContent` varchar(1024) DEFAULT NULL, `EveDesc` varchar(256) DEFAULT NULL, PRIMARY KEY (`NodeID`,`FltID`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- InnoDB有索引DROP TABLE `flt_evecurrent`;CREATE TABLE `flt_evecurrent` ( `NodeID` int(11) NOT NULL DEFAULT '0', `FltID` int(11) NOT NULL DEFAULT '0', `ObjID` int(11) DEFAULT NULL, `StationID` int(11) DEFAULT NULL, `EveType` int(11) DEFAULT NULL, `Severity` int(11) DEFAULT NULL, `ReportTime` date DEFAULT NULL, `CreateTime` date DEFAULT NULL, `EveContent` varchar(1024) DEFAULT NULL, `EveDesc` varchar(256) DEFAULT NULL, PRIMARY KEY (`NodeID`,`FltID`), KEY `ObjID` (`ObjID`), KEY `CreateTime` (`CreateTime`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;