MySQL支持的两种主要表存储格式MyISAM,InnoDB,上个月做个项目时,先使用了InnoDB,结果速度特别慢,1秒钟只能插入10几条。后来换成MyISAM格式,一秒钟插入上万条。当时觉的这两个表的性能也差别太大了吧。后来自己推测,不应该差别这么慢,估计是写的插入语句有问题,决定做个测试: 字串5
测试环境:Redhat Linux9,4CPU,内存2G,MySQL版本为4.1.6-gamma-standard
测试程序:Python+Python-MySQL模块。 字串7
测试方案:
字串2
1、MyISAM格式分别测试,事务和不用事务两种情况: 字串1
2、InnoDB格式分别测试AutoCommit=1(不用begin transaction和用begin transaction模式),AutoCommit=0 (不用begin transaction和用begin transaction模式)四种情况。 字串8
测试方法为插入10000条记录。为了测试不互相影响,单独建立了专用的测试表,建表语句如下:
字串2
1、MyISAM不用事务表: 字串5
| 以下为引用的内容: CREATE TABLE `MyISAM_NT` ( 字串5 `TableId` int(11) NOT NULL default '0', 字串4 `TableString` varchar(21) NOT NULL default '' 字串5
) ENGINE=MyISAM; 字串3 |
2、MyISAM用事务表:
字串6
| 以下为引用的内容: CREATE TABLE `MyISAM_TS` ( 字串4 `TableId` int(11) NOT NULL default '0', 字串7
`TableString` varchar(21) NOT NULL default '' 字串7 ) ENGINE=MyISAM; 字串4 |
3、InnoDB关闭AutoCommit,不用事务:
字串1
| 以下为引用的内容: CREATE TABLE `INNODB_NA_NB` ( 字串4 `TableId` int(11) NOT NULL default '0', 字串1 `TableString` varchar(21) NOT NULL default '' 字串1 ) ENGINE=InnoDB; 字串2
|
字串9
4、InnoDB关闭AutoCommit,用事务:
字串2
| 以下为引用的内容: CREATE TABLE `INNODB_NA_BE` ( 字串7 `TableId` int(11) NOT NULL default '0', 字串1 `TableString` varchar(21) NOT NULL default '' 字串7 ) ENGINE=InnoDB; 字串8 |
5、InnoDB开启AutoCommit,不用事务: 字串9
| 以下为引用的内容: CREATE TABLE `INNODB_AU_NB` ( 字串7 `TableId` int(11) NOT NULL default '0', 字串1 `TableString` varchar(21) NOT NULL default '' 字串9 ) ENGINE=InnoDB; 字串7 |
6、InnoDB开启AutoCommit,用事务: 字串7
| 以下为引用的内容: CREATE TABLE `INNODB_AU_BE` ( 字串6 `TableId` int(11) NOT NULL default '0', 字串1 `TableString` varchar(21) NOT NULL default '' 字串3 ) ENGINE=InnoDB; 字串3 测试的Python脚本如下: 字串3 #!/usr/bin/env Python 字串1 ''' 字串1
|
字串9
MyISAM,InnoDB性能比较 字串3
作者:空心菜(Invalid) 字串7
时间:2004-10-22
字串1
| 以下为引用的内容: ''' 字串8
import MySQLdb 字串5 import sys 字串2 import os 字串3 import string 字串2 import time 字串5 c = None 字串6
testtables = [("MyISAM_NT",None,0), 字串5 ("MyISAM_TS",None,1), 字串5 ("INNODB_NA_NB",0,0), 字串1
("INNODB_NA_BE",0,1), 字串4 ("INNODB_AU_NB",1,0), 字串4 ("INNODB_AU_BE",1,1) 字串8 ] 字串2 def BeginTrans(): 字串5 print "ExecSQL:BEGIN;" 字串1 c.execute("BEGIN;") 字串3 return 字串2
def Commit(): 字串6 print "ExecSQL:COMMIT;" 字串2 c.execute("COMMIT;") 字串2
return 字串8 def AutoCommit(flag): 字串4 print "ExecSQL:Set AUTOCOMMIT = "+str(flag) 字串4 c.execute("Set AUTOCOMMIT = "+str(flag)) 字串1 return 字串5 def getcount(table): 字串6 #print "ExecSQL:select count(*) from "+table 字串8 c.execute("select count(*) from "+table) 字串8 return c.fetchall()[0][0] 字串7 def AddTable (Table,TableId,TableString): 字串3 sql = "INSERT INTO "+Table+"(TableId, TableString) VALUES( "+ TableId+ ",'" + TableString +"')" 字串9 try: 字串2
c.execute(sql) 字串7 except MySQLdb.OperationalError,error: 字串4 print "AddTable Error:",error 字串1 return -1; 字串2 return c.rowcount 字串8 def main(): 字串9 argv = sys.argv 字串3 if len(argv) < 2: 字串7 print 'Usage:',argv[0],' TableId TestCount \n' 字串7
sys.exit(1) 字串8
global c #MySQL访问cursor 字串5
db_host = "localhost" 字串3
db_name = "demo" 字串1 db_user = "root" 字串1
db_user_passwd = "" 字串1 print "Config:[%s %s/%s %s] DB\n"%(db_host,db_user,db_user_passwd,db_name) 字串8 if len(argv) > 2: 字串4 tableid = argv[1] 字串7
testcount = int(argv[2]) # 字串4 for test in testtables: 字串6
|
字串1
#每次操作前都重写建立数据库连接 字串8
| 以下为引用的内容: try: 字串6 mdb = MySQLdb.connect(db_host, db_user, db_user_passwd, db_name) 字串3 except MySQLDb.OperationalError,error: 字串8 print "Connect MySQL[%s %s/%s %s] DB Error:"%(db_host,db_user,db_user_passwd,db_name),error,"\n" 字串5 sys.exit(1) 字串7 else: 字串2 c = mdb.cursor() 字串9
table,autocommit,trans = test 字串9 starttime = time.time() 字串3
print table," ",time.strftime("%y-%m-%d %H:%M:%S",time.localtime()) 字串9
if autocommit != None: 字串7 AutoCommit(autocommit) 字串6 if trans == 1: 字串7 BeginTrans() 字串2 for i in xrange(testcount): 字串6 tablestring = "%020d"%i 字串2 if (AddTable(table,tableid,tablestring)<1): 字串6 print "AddTable Error",tablestring 字串2 if trans == 1: 字串6
Commit() 字串2 print time.strftime("%y-%m-%d %H:%M:%S",time.localtime()) 字串3
endtime = time.time() 字串2 usedtime = endtime-starttime 字串7
print table,"count:",getcount(table)," used time:",usedtime 字串2 c.close() 字串4 mdb.close() 字串7 if __name__ == '__main__': 字串3 main() 字串2 测试结果如下: 字串6 Config:[localhost root/ demo] DB 字串5
MyISAM_NT 04-10-22 16:33:24 字串5
04-10-22 16:33:26 字串5 MyISAM_NT count: 10000 used time: 2.1132440567 字串1 MyISAM_TS 04-10-22 16:33:26 字串3
ExecSQL:BEGIN; 字串8 ExecSQL:COMMIT; 字串6 04-10-22 16:33:29 字串6
MyISAM_TS count: 10000 used time: 2.65475201607 字串2 INNODB_NA_NB 04-10-22 16:33:29 字串9 ExecSQL:Set AUTOCOMMIT = 0 字串3
04-10-22 16:33:31 字串4 INNODB_NA_NB count: 10000 used time: 2.51947999001 字串6 INNODB_NA_BE 04-10-22 16:33:31 字串7 ExecSQL:Set AUTOCOMMIT = 0 字串8 ExecSQL:BEGIN; 字串4
ExecSQL:COMMIT; 字串1 04-10-22 16:33:35 字串1 INNODB_NA_BE count: 10000 used time: 3.85625100136 字串5 INNODB_AU_NB 04-10-22 16:33:35 字串8 ExecSQL:Set AUTOCOMMIT = 1 字串1
04-10-22 16:34:19 字串2 INNODB_AU_NB count: 10000 used time: 43.7153041363 字串5 INNODB_AU_BE 04-10-22 16:34:19 字串7 ExecSQL:Set AUTOCOMMIT = 1 字串3
ExecSQL:BEGIN; 字串8
ExecSQL:COMMIT; 字串2 04-10-22 16:34:22 字串6 INNODB_AU_BE count: 10000 used time: 3.14328193665 字串7 |
字串8
结论:
字串5
由此得知影响速度的主要原因是AUTOCOMMIT默认设置是打开的, 字串9
我当时的程序没有显式调用BEGIN;开始事务,导致每插入一条都自动Commit,严重影响了速度。
算来也是个低级错误!
相关参考:
http://dev.mysql.com/doc/MySQL/en/COMMIT.html
http://dev.mysql.com/doc/MySQL/en/InnoDB_and_AUTOCOMMIT.html
字串7