mysql的项目,需要设计一个快速上载的机制
最后的解决办法是利用了mysql的预处理语句的特性实现的
mysql的预处理语句支持多行数据的预处理,即insertinto(columnName,columnName,)values(,,)(,,)
这样你在绑定输入参数的时候可以在程序里将整张表的数据都绑定好然后调用一次执行就能将整张表的数据插入,比用mysql_query一行一行插入省的几倍的时间
不过你一次发到mysql服务器端的数据多的情况下,要设置my
ini文件下的一个配置项,把服务器允许一次发送的数据包的大小调大就行
首先说一下,IProvider里有一个用于实现批量插入的插件服务接口IBatcherProvider,此接口在前一篇文章中已经提到过了。///<summary>/// 提供数据批量处理的方法。 ///</summary>publicinterface IBatcherProvider : IProviderService { ///<summary>/// 将<see cref="DataTable"/> 的数据批量插入到数据库中。 ///</summary>///<param name="dataTable">要批量插入的 <see cref="DataTable"/>。</param>///<param name="batchSize">每批次写入的数据量。</param>void Insert(DataTable dataTable, int batchSize = 10000); }一、SqlServer数据批量插入SqlServer的批量插入很简单,使用SqlBulkCopy就可以,以下是该类的实现:///<summary>/// 为SystemDataSqlClient 提供的用于批量 *** 作的方法。 ///</summary>publicsealedclass MsSqlBatcher : IBatcherProvider { ///<summary>/// 获取或设置提供者服务的上下文。 ///</summary>public ServiceContext ServiceContext { get; set; } ///<summary>/// 将<see cref="DataTable"/> 的数据批量插入到数据库中。 ///</summary>///<param name="dataTable">要批量插入的 <see cref="DataTable"/>。</param>///<param name="batchSize">每批次写入的数据量。</param>publicvoid Insert(DataTable dataTable, int batchSize = 10000) { CheckerArgumentNull(dataTable, "dataTable"); if (dataTableRowsCount == 0) { return; } using (var connection = (SqlConnection)ServiceContextDatabaseCreateConnection()) { try { connectionTryOpen(); //给表名加上前后导符var tableName = DbUtilityFormatByQuote(ServiceContextDatabaseProviderGetService<ISyntaxProvider>(), dataTableTableName); using (var bulk = new SqlBulkCopy(connection, SqlBulkCopyOptionsKeepIdentity, null) { DestinationTableName = tableName, BatchSize = batchSize }) { //循环所有列,为bulk添加映射 dataTableEachColumn(c => bulkColumnMappingsAdd(cColumnName, cColumnName), c => !cAutoIncrement); bulkWriteToServer(dataTable); bulkClose(); } } catch (Exception exp) { thrownew BatcherException(exp); } finally { connectionTryClose(); } } } }以上没有使用事务,使用事务在性能上会有一定的影响,如果要使用事务,可以设置SqlBulkCopyOptionsUseInternalTransaction。二、Oracle数据批量插入SystemDataOracleClient不支持批量插入,因此只能使用OracleDataAccess组件来作为提供者。///<summary>/// OracleDataAccess 组件提供的用于批量 *** 作的方法。 ///</summary>publicsealedclass OracleAccessBatcher : IBatcherProvider { ///<summary>/// 获取或设置提供者服务的上下文。 ///</summary>public ServiceContext ServiceContext { get; set; } ///<summary>/// 将<see cref="DataTable"/> 的数据批量插入到数据库中。 ///</summary>///<param name="dataTable">要批量插入的 <see cref="DataTable"/>。</param>///<param name="batchSize">每批次写入的数据量。</param>publicvoid Insert(DataTable dataTable, int batchSize = 10000) { CheckerArgumentNull(dataTable, "dataTable"); if (dataTableRowsCount == 0) { return; } using (var connection = ServiceContextDatabaseCreateConnection()) { try { connectionTryOpen(); using (var command = ServiceContextDatabaseProviderDbProviderFactoryCreateCommand()) { if (command == null) { thrownew BatcherException(new ArgumentException("command")); } commandConnection = connection; commandCommandText = GenerateInserSql(ServiceContextDatabase, command, dataTable); commandExecuteNonQuery(); } } catch (Exception exp) { thrownew BatcherException(exp); } finally { connectionTryClose(); } } } ///<summary>/// 生成插入数据的sql语句。 ///</summary>///<param name="database"></param>///<param name="command"></param>///<param name="table"></param>///<returns></returns>privatestring GenerateInserSql(IDatabase database, DbCommand command, DataTable table) { var names = new StringBuilder(); var values = new StringBuilder(); //将一个DataTable的数据转换为数组的数组var data = tableToArray(); //设置ArrayBindCount属性 commandGetType()GetProperty("ArrayBindCount")SetValue(command, tableRowsCount, null); var syntax = databaseProviderGetService<ISyntaxProvider>(); for (var i = 0; i < tableColumnsCount; i++) { var column = tableColumns[i]; var parameter = databaseProviderDbProviderFactoryCreateParameter(); if (parameter == null) { continue; } parameterParameterName = columnColumnName; parameterDirection = ParameterDirectionInput; parameterDbType = columnDataTypeGetDbType(); parameterValue = data[i]; if (namesLength > 0) { namesAppend(","); valuesAppend(","); } namesAppendFormat("{0}", DbUtilityFormatByQuote(syntax, columnColumnName)); valuesAppendFormat("{0}{1}", syntaxParameterPrefix, columnColumnName); commandParametersAdd(parameter); } returnstringFormat("INSERT INTO {0}({1}) VALUES ({2})", DbUtilityFormatByQuote(syntax, tableTableName), names, values); } }以上最重要的一步,就是将DataTable转为数组的数组表示,即object[][],前数组的上标是列的个数,后数组是行的个数,因此循环Columns将后数组作为Parameter的值,也就是说,参数的值是一个数组。而insert语句与一般的插入语句没有什么不一样。三、SQLite数据批量插入SQLite的批量插入只需开启事务就可以了,这个具体的原理不得而知。publicsealedclass SQLiteBatcher : IBatcherProvider { ///<summary>/// 获取或设置提供者服务的上下文。 ///</summary>public ServiceContext ServiceContext { get; set; } ///<summary>/// 将<see cref="DataTable"/> 的数据批量插入到数据库中。 ///</summary>///<param name="dataTable">要批量插入的 <see cref="DataTable"/>。</param>///<param name="batchSize">每批次写入的数据量。</param>publicvoid Insert(DataTable dataTable, int batchSize = 10000) { CheckerArgumentNull(dataTable, "dataTable"); if (dataTableRowsCount == 0) { return; } using (var connection = ServiceContextDatabaseCreateConnection()) { DbTransaction transcation = null; try { connectionTryOpen(); transcation = connectionBeginTransaction(); using (var command = ServiceContextDatabaseProviderDbProviderFactoryCreateCommand()) { if (command == null) { thrownew BatcherException(new ArgumentException("command")); } commandConnection = connection; commandCommandText = GenerateInserSql(ServiceContextDatabase, dataTable); if (commandCommandText == stringEmpty) { return; } var flag = new AssertFlag(); dataTableEachRow(row => { var first = flagAssertTrue(); ProcessCommandParameters(dataTable, command, row, first); commandExecuteNonQuery(); }); } transcationCommit(); } catch (Exception exp) { if (transcation != null) { transcationRollback(); } thrownew BatcherException(exp); } finally { connectionTryClose(); } } } privatevoid ProcessCommandParameters(DataTable dataTable, DbCommand command, DataRow row, bool first) { for (var c = 0; c < dataTableColumnsCount; c++) { DbParameter parameter; //首次创建参数,是为了使用缓存if (first) { parameter = ServiceContextDatabaseProviderDbProviderFactoryCreateParameter(); parameterParameterName = dataTableColumns[c]ColumnName; commandParametersAdd(parameter); } else { parameter = commandParameters[c]; } parameterValue = row[c]; } } ///<summary>/// 生成插入数据的sql语句。 ///</summary>///<param name="database"></param>///<param name="table"></param>///<returns></returns>privatestring GenerateInserSql(IDatabase database, DataTable table) { var syntax = databaseProviderGetService<ISyntaxProvider>(); var names = new StringBuilder(); var values = new StringBuilder(); var flag = new AssertFlag(); tableEachColumn(column => { if (!flagAssertTrue()) { namesAppend(","); valuesAppend(","); } namesAppend(DbUtilityFormatByQuote(syntax, columnColumnName)); valuesAppendFormat("{0}{1}", syntaxParameterPrefix, columnColumnName); }); returnstringFormat("INSERT INTO {0}({1}) VALUES ({2})", DbUtilityFormatByQuote(syntax, tableTableName), names, values); } } 四、MySql数据批量插入///<summary>/// 为MySqlData 组件提供的用于批量 *** 作的方法。 ///</summary>publicsealedclass MySqlBatcher : IBatcherProvider { ///<summary>/// 获取或设置提供者服务的上下文。 ///</summary>public ServiceContext ServiceContext { get; set; } ///<summary>/// 将<see cref="DataTable"/> 的数据批量插入到数据库中。 ///</summary>///<param name="dataTable">要批量插入的 <see cref="DataTable"/>。</param>///<param name="batchSize">每批次写入的数据量。</param>publicvoid Insert(DataTable dataTable, int batchSize = 10000) { CheckerArgumentNull(dataTable, "dataTable"); if (dataTableRowsCount == 0) { return; } using (var connection = ServiceContextDatabaseCreateConnection()) { try { connectionTryOpen(); using (var command = ServiceContextDatabaseProviderDbProviderFactoryCreateCommand()) { if (command == null) { thrownew BatcherException(new ArgumentException("command")); } commandConnection = connection; commandCommandText = GenerateInserSql(ServiceContextDatabase, command, dataTable); if (commandCommandText == stringEmpty) { return; } commandExecuteNonQuery(); } } catch (Exception exp) { thrownew BatcherException(exp); } finally { connectionTryClose(); } } } ///<summary>/// 生成插入数据的sql语句。 ///</summary>///<param name="database"></param>///<param name="command"></param>///<param name="table"></param>///<returns></returns>privatestring GenerateInserSql(IDatabase database, DbCommand command, DataTable table) { var names = new StringBuilder(); var values = new StringBuilder(); var types = new List<DbType>(); var count = tableColumnsCount; var syntax = databaseProviderGetService<ISyntaxProvider>(); tableEachColumn(c => { if (namesLength > 0) { namesAppend(","); } namesAppendFormat("{0}", DbUtilityFormatByQuote(syntax, cColumnName)); typesAdd(cDataTypeGetDbType()); }); var i = 0; foreach (DataRow row in tableRows) { if (i > 0) { valuesAppend(","); } valuesAppend("("); for (var j = 0; j < count; j++) { if (j > 0) { valuesAppend(", "); } var isStrType = IsStringType(types[j]); var parameter = CreateParameter(databaseProvider, isStrType, types[j], row[j], syntaxParameterPrefix, i, j); if (parameter != null) { valuesAppend(parameterParameterName); commandParametersAdd(parameter); } elseif (isStrType) { valuesAppendFormat("'{0}'", row[j]); } else { valuesAppend(row[j]); } } valuesAppend(")"); i++; } returnstringFormat("INSERT INTO {0}({1}) VALUES {2}", DbUtilityFormatByQuote(syntax, tableTableName), names, values); } ///<summary>/// 判断是否为字符串类别。 ///</summary>///<param name="dbType"></param>///<returns></returns>privatebool IsStringType(DbType dbType) { return dbType == DbTypeAnsiString || dbType == DbTypeAnsiStringFixedLength || dbType == DbTypeString || dbType == DbTypeStringFixedLength; } ///<summary>/// 创建参数。 ///</summary>///<param name="provider"></param>///<param name="isStrType"></param>///<param name="dbType"></param>///<param name="value"></param>///<param name="parPrefix"></param>///<param name="row"></param>///<param name="col"></param>///<returns></returns>private DbParameter CreateParameter(IProvider provider, bool isStrType, DbType dbType, object value, char parPrefix, int row, int col) { //如果生成全部的参数,则速度会很慢,因此,只有数据类型为字符串(包含'号)和日期型时才添加参数if ((isStrType && valueToString()IndexOf('\'') != -1) || dbType == DbTypeDateTime) { var name = stringFormat("{0}p_{1}_{2}", parPrefix, row, col); var parameter = providerDbProviderFactoryCreateParameter(); parameterParameterName = name; parameterDirection = ParameterDirectionInput; parameterDbType = dbType; parameterValue = value; return parameter; } returnnull; } }MySql的批量插入,是将值全部写在语句的values里,例如,insert batcher(id, name) values(1, '1', 2, '2', 3, '3', 10, '10')。五、测试接下来写一个测试用例来看一下使用批量插入的效果。
可以使用oracle sql loader批量导入数据:
生成测试数据的EXCEL文件,把EXCEL文件另存为CSV(逗号分隔)(csv),控制文件设置为用逗号分隔。
示例:
LOAD DATA
INFILE ‘d:\carcsv’
APPEND INTO TABLE t_car_temp
FIELDS TERMINATED BY ","
(phoneno,vip_car)
保存为inputctl
最后在命令行下输入:
C:\>sqlldr userid=system/manager
control=inputctl(在unix环境下亦同)
默认日志文件名为:inputlog
默认坏记录文件为:inputbad
常见的insert语句,向数据库中,一条语句只能插入一条数据:
insert into persons
(id_p, lastname , firstName, city )
values(204,'haha' , 'deng' , 'shenzhen');
(如上,仅插入了一条记录)
怎样一次insert插入多条记录呢?
使用示例:
insert into persons
(id_p, lastname , firstName, city )
values
(200,'haha' , 'deng' , 'shenzhen'),
(201,'haha2' , 'deng' , 'GD'),
(202,'haha3' , 'deng' , 'Beijing');
这样就批量插入数据了, 遵循这样的语法,就可以批量插入数据了。
执行成功,截图:
据说,在程序开发中,一次插入多条数据,比逐次一条一条的插入数据,效率高很多
所以在程序开发的时候,使用此批量插入,也是比较不错的。
此语句在MySQL 5, postgreSQL 93执行通过。
导入时把生成索引给关掉,应该能快一点
不要一边导入一边建立索引
8G数据,应该也不那么慢了
把sql语句文件读取出一部分看看,建表语句中,应当有建立索引的部分,删掉它!
只做建表和插入数据两件事
还有,看看数据库有没有外键
尽量在插入数据过程中去掉外键关联
等数据插入完成之后再加索引和外键,应该能提高很多读写性能
截取一部分数据,例如100Mb
插入一下试试,可以预先对整体时间有一个预期
还有,真的要弄台好点的电脑,或者去借一台,等把数据导入完成之后,把msyql的库文件直接复制出来放自己机器上跑就好
emm
再追加点信息,要先搞明白,sql原文件里,到底都执行了哪几类 *** 作
可能需要你用c之类写点小工具,或者别的什么语言,分块读取并处理文件
8G
嗯,还好
现在内存都够大,否则你都没法直接用软件打开了
只有8G也可以直接用软件打开看
停掉索引真的可以大幅度加快插入数据的速度
建议试一试!
添加数据需要知道往哪张表添加,以及自己要添加的内容,然后可用insert语句执行。
1、以sqlserver2008r2为例,登录SQL Server Management Studio到指定的数据库。
2、登录后点击“新建查询”。
3、比如要往test表中插入数据,可先用如下语句查看一下表结构及表内数据:
1select from test;4、根据自己的实际情况添加输入,比如要添加一条“16,du小小动”的数据。
1insert into test (id,name) values (16,'du小小动');执行成功后会有提示:
5、此时数据库中数据如下,说明添加成功。
以上就是关于大批量插入数据,mysql批量更新与插入多种(数据库批量更新大量数据)全部的内容,包括:大批量插入数据,mysql批量更新与插入多种(数据库批量更新大量数据)、几种数据库的大数据批量插入【转】、如何在数据库中批量插入数据等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)