怎样在mysql中插入大量的数据

怎样在mysql中插入大量的数据,第1张

方法一,从已有大数据表中检索大量数据插入到目标表里;

方法二,编写存储过程,利用循环向数据表中插入大量的固定或有规律变化或随机变化的虚拟数据;

方法三,通过应用程序端编程向目标表插入大量的数据,手法与方法二类似。

首先说一下,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')。五、测试接下来写一个测试用例来看一下使用批量插入的效果。

首先, 插入上万条数据,对于数据库来说并不是“很大”的工作量,一般配置的笔记本电脑都可以在1分钟内完成。 所以最简单、最灵活的办法还是写SQL语句。

如果不希望DB编译器每次执行都编译SQL的话,可以使用存储过程,直接调用,性能上会好很多。也比较简单。

(几万条数据怎么地也得要时间去处理,所以不可能特别快的。)

如果由于各种原因,导致这个插入还是很慢, 而且你的MYSQL又是50以上版本的话,可以使用BulkCopy来进行批量 *** 作。

BulkCopy的原理就是Client直接把一个数组(DataTable)传给DB,然后传入表名,所有的编译、 *** 作都由DB自己完成,效率很高。

引用MySqlDatadll , 调用MysqlBulkCopy函数即可。

这个函数在处理海量数据插入的时候效率尤为明显, 小量数据反而没什么优势,而且由于传入的DataTable格式必须和表的字段一模一样(空的列也要传进去),导致C#要写很多代码来构造这个数组,所以要你自己权衡用还是不用。

我在自己的电脑上批量插入一亿条数据,Insert写法大概需要1小时,BulkCopy大概只需要5分钟。

但是应该可以直接调用

SQL

语句吧,我可以在外面组织好

类似

insert

into

new_table(f1,f2,f3)

select

f1,f2,f3

from

old_table;的语句,只要

CI

能够正常调用,并返回执行结果就可以了啊?

还有

$this->db->insert('new_table',$data);与

$this->db->update('new_table',$data);是不是都没有返回结果啊?如果对于有一个自动增量的字段的表,插入时可以不管,系统自动生成,如何得到刚刚新插入记录的自动增量的字段的值呢?

一般这个字段还都是唯一的标识字段的

导入时把生成索引给关掉,应该能快一点

不要一边导入一边建立索引

8G数据,应该也不那么慢了

把sql语句文件读取出一部分看看,建表语句中,应当有建立索引的部分,删掉它!

只做建表和插入数据两件事

还有,看看数据库有没有外键

尽量在插入数据过程中去掉外键关联

等数据插入完成之后再加索引和外键,应该能提高很多读写性能

截取一部分数据,例如100Mb

插入一下试试,可以预先对整体时间有一个预期

还有,真的要弄台好点的电脑,或者去借一台,等把数据导入完成之后,把msyql的库文件直接复制出来放自己机器上跑就好

emm

再追加点信息,要先搞明白,sql原文件里,到底都执行了哪几类 *** 作

可能需要你用c之类写点小工具,或者别的什么语言,分块读取并处理文件

8G

嗯,还好

现在内存都够大,否则你都没法直接用软件打开了

只有8G也可以直接用软件打开看

停掉索引真的可以大幅度加快插入数据的速度

建议试一试!

以上就是关于怎样在mysql中插入大量的数据全部的内容,包括:怎样在mysql中插入大量的数据、几种数据库的大数据批量插入【转】、c#中往mysql里批量插入上万条数据,有比较高效的方法吗等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/sjk/9537740.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-29
下一篇2023-04-29

发表评论

登录后才能评论

评论列表(0条)

    保存