C#在MySQL大量数据下的高效读取、写入详解_C#教程

前言

C#操作MySQL大量数据最常见的操作便是 select 读取数据,然后在C#中对数据进行处理, 完毕后再插入数据库中。  简而言之就 select -> process -> insert 三个步骤。 对于数据量小的情况下(百万级别 or 几百兆)可能

最多1个小时就处理完了。但是对于千万级数据可能几天,甚至更多。 那么问题来了,如何优化??

第一步 解决读取的问题

跟数据库打交道的方式有很多,我来列举下吧:

1. 【重武器-坦克大炮】使用重型ORM框架,比如 EF,NHibernat 这样的框架。

2. 【轻武器-AK47】 使用 Dapper,PetaPoco 之类,单cs文件。灵活高效,使用简单。居家越货必备(我更喜欢PetaPoco :))

3. 【冷兵器?匕首?】使用原生的Connection、Command。 然后写原生的SQL语句。。

分析:

【重武器】在我们这里肯定直接被PASS, 他们应该被用在大型项目中。

【轻武器】 Dapper,PetaPoco 看过源码你会发现用到了反射,虽然使用 IL和缓存技术 ,但是还是会影响读取效率,PASS

好吧那就只有使用匕首, 原生SQL 走起, 利用 DataReader 进行高效读取,并且使用 索引 取数据(更快),而不是列名。

大概的代码如下:

using (var conn = new MySqlConnection("Connection String..."))
{
 conn.Open();
 //此处设置读取的超时,不然在海量数据时很容易超时
 var c = new MySqlCommand("set net_write_timeout=9999999; set net_read_timeout=9999999", conn);
 c.ExecuteNonQuery();

 MySqlCommand rcmd = new MySqlCommand();
 rcmd.Connection = conn;
 rcmd.CommandText = @"SELECT `f1`,`f2` FROM `table1`";
 //设置命令的执行超时
 rcmd.CommandTimeout = 99999999;
 var myData = rcmd.ExecuteReader();

 while (myData.Read())
 {
  var f1= myData.GetInt32(0);
  var f2= myData.GetString(1);
  //这里做数据处理....
 }
}

哈哈,怎么样,代码非常原始,还是使用索引来取数据,很容易出错。  当然一切为了性能咱都忍了

第二步 数据处理

其实这一步,根据你的业务需要,代码肯定不一, 不过无非是一些 字符串处理 , 类型转换 的操作,这时候就是考验你的C#基础功底的时候了。 以及如何高效编写正则表达式。。。

具体代码也没法写啊 ,先看完 CLR via C# 在来跟我讨论吧 ,O(∩_∩)O哈哈哈~ 跳过。。。。

第三部 数据插入

如何批量插入才最高效呢?  有同学会说, 使用 事务 啊,BeginTransaction, 然后EndTransaction。 恩,这个的确可以提高插入效率。 但是还有更加高效的方法,那就是合并insert语句。

那么怎么合并呢?

insert into table (f1,f2) values(1,'sss'),values(2,'bbbb'),values(3,'cccc');

就是把values后面的全部用逗号,链接起来,然后一次性执行 。

当然不能一次性提交个100MB的SQL执行,MySQL服务器对每次执行命令的长度是有限制的。 通过 MySQL服务器端的 max_allowed_packet   属性可以查看, 默认是 1MB

咱们来看看伪代码吧

 //使用StringBuilder高效拼接字符串
 var sqlBuilder = new StringBuilder();
 //添加insert 语句的头
 string sqlHeader = "insert into table1 (`f1`,`f2`) values";
 sqlBuilder.Append(sqlHeader);
 using (var conn = new MySqlConnection("Connection String..."))
 {
  conn.Open();
  //此处设置读取的超时,不然在海量数据时很容易超时
  var c = new MySqlCommand("set net_write_timeout=9999999; set net_read_timeout=9999999", conn);
  c.ExecuteNonQuery();

  MySqlCommand rcmd = new MySqlCommand();
  rcmd.Connection = conn;
  rcmd.CommandText = @"SELECT `f1`,`f2` FROM `table1`";
  //设置命令的执行超时
  rcmd.CommandTimeout = 99999999;
  var myData = rcmd.ExecuteReader();
  while (myData.Read())
  {
   var f1 = myData.GetInt32(0);
   var f2 = myData.GetString(1);
   //这里做数据处理....
   sqlBuilder.AppendFormat("({0},'{1}'),", f1,AddSlash(f2));
   if (sqlBuilder.Length >= 1024 * 1024 * 1024)//当然这里的1MB length的字符串并不等于 1MB的Packet。。。我知道:)
   {
    insertCmd.Execute(sqlBuilder.Remove(sqlBuilder.Length-1,1).ToString())//移除逗号,然后执行
    sqlBuilder.Clear();//清空
    sqlBuilder.Append(sqlHeader);//在加上insert 头
   }
  }
}

好了,到这里 大概的优化后的高效查询、插入就完成了。

总结

总结下来,无非2个关键技术点, DataReader、SQL合并, 都是一些老的技术啦。其实,上面的代码只能称得上高效, 但是, 却非常的不优雅。以上就是这篇文章的全部内容了,希望本文的内容对大家能有所帮助,如果有疑问大家可以留言交流。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索c
, mysql
, 优化
, 操作mysql数据库
, 大量写入
读取大量数据
c站、c语言、cf、ch、c罗,以便于您获取更多的相关知识。

时间: 2024-08-28 01:51:39

C#在MySQL大量数据下的高效读取、写入详解_C#教程的相关文章

C#如何在海量数据下的高效读取写入MySQL_Mysql

前提 由于工作的原因,经常需要对海量数据进行处理,做的数据爬虫相关,动辄千万级别的数据,单表几十个G都是都是家常便饭.  主要开发语言是C#,数据库使用的是MySQL. 最常见的操作便是 select 读取数据,然后在C#中对数据进行处理, 完毕后再插入数据库中.  简而言之就 select -> process -> insert三个步骤. 对于数据量小的情况下(百万级别 or 几百兆)可能最多1个小时就处理完了.但是对于千万级数据可能几天,甚至更多. 那么问题来了,如何优化??  (数据库

大数据下高并发的处理详解

对于我们开发的网站,如果网站的访问量非常大的话,那么我们就需要考虑相关的并发访问问题了.而并发问题是绝大部分的程序员头疼的问题,但话又说回来了,既然逃避不掉,那我们就要想想应对措施,今天我们就一起讨论一下常见的并发和同步吧. 首先为了更好的理解并发和同步,我们需要首先明白两个重要的概念:同步和异步 同步和异步的区别和联系 所谓同步,就是一个线程执行一个方法或函数的时候,会阻塞其它线程,其他线程要等待它执行完毕才能继续执行.异步,就是多个线程之间没有阻塞,多个线程同时执行.通俗一点来说,同步就是一

MySQL大数据量之导入导出命令详解

面对大数据量,大文件的sql操作,我们需要借助mysql强大的命令操作: 1. 数据库导入命令  代码如下 复制代码 mysql -h localhost -u root -p   use dbname source backup.sql 说明:需要使用命令连接上数据库并选择相应数据库才能使用. 2. 数据库备份命令 MySQL的导出命令mysqldump,基本用法是:  代码如下 复制代码 mysqldump [OPTIONS] database [tables] 说明:不能先连接数据库,是直

深入N皇后问题的两个最高效算法的详解_C 语言

N皇后问题是一个经典的问题,在一个N*N的棋盘上放置N个皇后,每行一个并使其不能互相攻击(同一行.同一列.同一斜线上的皇后都会自动攻击).一. 求解N皇后问题是算法中回溯法应用的一个经典案例回溯算法也叫试探法,它是一种系统地搜索问题的解的方法.回溯算法的基本思想是:从一条路往前走,能进则进,不能进则退回来,换一条路再试.在现实中,有很多问题往往需要我们把其所有可能穷举出来,然后从中找出满足某种要求的可能或最优的情况,从而得到整个问题的解.回溯算法就是解决这种问题的"通用算法",有&qu

基于linux下获取时间函数的详解_C 语言

//-------------------------------------------------------------//asctime(将时间和日期以字符串格式表示)#include<time.h>定义函数char * asctime(const struct tm * timeptr);函数说明asctime()将参数timeptr所指的tm结构中的信息转换成真实世界所使用的时间日期表示方法,然后将结果以字符串形态返回.此函数已经由时区转换成当地时间,字符串格式为:"We

MySQL数据备份之mysqldump的使用详解_Mysql

mysqldump常用于MySQL数据库逻辑备份. 1.各种用法说明 A. 最简单的用法: mysqldump -uroot -pPassword [database name] > [dump file] 上述命令将指定数据库备份到某dump文件(转储文件)中,比如: mysqldump -uroot -p123 test > test.dump 生成的test.dump文件中包含建表语句(生成数据库结构哦)和插入数据的insert语句. B. --opt 如果加上--opt参数则生成的du

MySQL 中修改密码及访问限制设置详解

mysql|访问|详解 MySQL中修改密码及访问限制设置详解 MySQL是一个真正的多用户.多线程SQL数据库服务器.MySQL是以一个客户机/服务器结构的实现,它由一个服务器守护程序mysqld和很多不同的客户程序和库组成.由于其源码的开放性及稳定性,且与网站流行编?挥镅?PHP的完美结合,现在很多站点都利用其当作后端数据库,使其获得了广泛应用.处于安全方面的考虑,需要为每一用户赋于对不同数据库的访问限制,以满足不同用户的要求.下面就分别讨论,供大家参考. 一.MySQL修改密码方法总结 首

mybatis实现对数据的增删查改实例详解_java

前期准备 新建java工程或java wweb工程,需要导入以下的包, 基本工作已经完成,接下来开始进入正题. 新建实体类 新建与数据库表对应的实体类 package com.edu.hpu.domain; /** * @author Administrator *user表所对应的实体类 */ public class User { //实体类的属性和表的字段名称一一对应 private int id; private String name; private int age; //对属性进行

Mysql的基础使用之MariaDB安装方法详解_Mysql

我首次用mysql是在ubuntu上,现在用的是linux 中的Red Hat 分支的centOS 7 ,安装时发现通常用的都是MariaDB 来代替mysql,通过资料查询发现Mariadb是mysql的其中的一种分支,由mysql的创始人带领的团队所开发的mysql分支的一种版本,因为mysql受到被Oracle收购后的日渐封闭与缓慢的更新,众多Linux发行版逐渐抛弃了这个人气开源数据库,使MySQL在各大Linux发行版中的失势由于不满MySQL被Oracle收购后的日渐封闭与缓慢的更新