有时候咱们须要将大量数据批量写入数据库,直接使用程序语言和Sql写入每每很耗时间,其中有一种方案就是使用MySql Load data infile导入文件的形式导入数据,这样可大大缩短数据导入时间。node
假如是从MySql客户端调用,将客户端的文件导入,则须要使用 load local data infile.mysql
LOAD DATA INFILE 语句以很高的速度从一个文本文件中读取行到一个表中。文件名必须是一个文字字符串。sql
1,开启load local data infile.数据库
假如是Linux下编译安装,c#
若是使用源码编译的MySQL,在configure的时候,须要添加参数:--enable-local-infile 客户端和服务器端都须要,不然不能使用local参数。安全
./configure --prefix=/usr/local/mysql --enable-local-infilebash
make install服务器
如果其它系统,可在配置文件中配置:工具
在MySql 配置文件My.ini文件中下面项中加入local-infile=1:学习
add:
[mysqld]
local-infile=1
[mysql]
local-infile=1
客户端和服务端度须要开启,对于客户端也能够在执行命中加上--local-infile=1 参数:
mysql --local-infile=1 -uroot -pyourpwd yourdbname
如:
如:/usr/local/mysql/bin/mysql -uroot -h192.168.0.2 -proot databaseName --local-infile=1 -e "LOAD DATA LOCAL INFILE 'data.txt' into table test(name,sex) "
2, 编码格式注意:
若包含中文,请保证导入文件、链接字符串、导入表都是UTF-8编码。
3,执行
在使用LOAD DATA到MySQL的时候,有2种状况:
(1)在远程客户端(须要添加选项:--local-infile=1)导入远程客户端文本到MySQL,需指定LOCAL(默认就是ignore),加ignore选项会放弃数据,加replace选项会更新数据,都不会出现惟一性约束问题。
[zhuxu@xentest9-vm1 tmp]$mysql -uzhuxu -pzhuxu test -h10.254.5.151 --local-infile=1--show-warnings -v -v -v \
> -e "LOAD DATA LOCAL INFILE '/tmp/2.txt' INTO TABLE tmp_loaddata FIELDS TERMINATED BY ','";
(2)在本地服务器导入本地服务器文本到MySQL,不指定LOACL,出现惟一性约束冲突,会失败回滚,数据导入不进去,这个时候就须要加ignore或者replace来导入数据。
mysql>LOAD DATA INFILE '/home/zhuxu/1.txt' INTO TABLE tmp_loaddata FIELDS TERMINATED BY ',';
4,事务分析
步骤是这样的:
1,开启binlog,设置binlog_format=row,执行reset master;
2,load data infile xxxxx;
3,查看binlog。
能够看出,总共是一个事务,也经过mysqlbinlog查看了binary log,确认中间是被拆分红了多个insert形式。因此load data infile基本上是这样执行的:
begin
insert into values(),(),(),()...
insert into values(),(),(),()...
insert into values(),(),(),()...
...
...
commit
固然,因为row格式的binlog的语句并非很明显的记录成多值insert语句,它的格式时
insert into table
set @1=
set @2=
...
set @n=
insert into table
set @1=
set @2=
...
set @n=
insert ...
;注意这里有一个分号‘;’,其实前面这一部分就至关于前面说的多值insert形式
而后接下来就重复上面的那种格式,也就是一个load data infile 拆成了多个多值insert语句。
前面说的是row格式记录的load data infile,那么对于statement是怎么样的呢?statement格式的binlog,它是这样记录的,binlog中仍是一样的load data语句,可是在记录load data 语句以前,它会先将你master上这个load data 使用到的csv格式的文件拆分红多个部分,而后传到slave上(在mysql的tmpdir下),固然传这些csv格式的文件也会记录binlog event,而后最后真正的SQL语句形式就是load data local infile '/tmp/SQL_X_Y'这种形式(这里假设mysql的tmpdir是默认的/tmp),实际上这样很危险,好比tmpdir空间不够,那就会报错。不过从效率上来讲二者可能差很少,由于statement格式的binlog也是拆分红了多个语句。
附:
(1)load data infile 和 load local data infile 在 innodb和MyISAM 同步方面的区别
对MyISAM引擎:
(1)对master服务器进行 ‘load’ 操做,
(2)在master上所操做的load.txt文件,会同步传输到slave上,并在tmp_dir 目录下生成 load.txt文件
master服务器插入了多少,就传给slave多少
(3)当master上的load操做完成后,传给slave的文件也结束时,
即:在slave上生成完整的 load.txt文件
此时,slave才开始从 load.txt 读取数据,并将数据插入到本地的表中
对innodb引擎:
(1)主数据库进行 ‘Load’ 操做
(2)主数据库操做完成后,才开始向slave传输 load.txt文件,
slave接受文件,并在 tmp_dir 目录下生成 load.txt 文件
接受并生成完整的load.txt 后,才开始读取该文件,并将数据插入到本地表中
异常状况处理:
1)对MyISAM引擎
当数据库执行load,此时若是中断:
Slave端将报错,例如:
####################################################################
Query partially completed on the master (error on master: 1053) and was aborted.
There is a chance that your master is inconsistent at this point.
If you are sure that your master is ok,
run this query manually on the slave and then restart the slave with SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;
START SLAVE; . Query: 'LOAD DATA INFILE '/tmp/SQL_LOAD-2-1-3.data' IGNORE INTO TABLE `test_1`
FIELDS TERMINATED BY ',' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (`id`, `name`, `address`)'
###########################################################################################
按照提示,在slave服务器上:
(1) 使用提示的load命令,将主服务器传输过来的load文件,在从服务器上执行
(2)让从服务器跳过错误。set global sql_slave_skip_counter=1;
(3)开启同步
2)对Innodb引擎
因为innodb是事务型的,因此会把load文件的整个操做看成一个事务来处理,
中途中断load操做,会致使回滚。
与此相关的一些参数:
max_binlog_cache_size----可以使用的最大cache内存大小。
当执行多语句事务时,max_binlog_cache_size若是不够大,
系统可能会报出“Multi-statement
transaction required more than 'max_binlog_cache_size' bytes of storage”的错误。
备注:以load data 来讲,若是load的文件大小为512M,在执行load 的过程当中,
全部产生的binlog会先写入binlog_cache_size,直到load data 的操做结束后,
最后,再由binlog_cache_size 写入二进制日志,如mysql-bin.0000008等。
因此此参数的大小必须大于所要load 的文件的大小,或者当前所要进行的事务操做的大小。
max_binlog_size------------Binlog最大值,通常设置为512M或1GB,但不能超过1GB。
该设置并不能严格控制Binlog的大小,尤为是Binlog遇到一根比较大事务时,
为了保证事务的完整性,不可能作切换日志的动做,只能将该事务的全部SQL都记录进
当前日志,直到事务结束
备注:有时能看到,binlog生成的大小,超过了设定的1G。这就是由于innodb某个事务的操做比较大,
不能作切换日志操做,就所有写入当前日志,直到事务结束。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
(2)C# 批量插入Mysql
public void loadData(Connection connection)
{
long starTime = System.currentTimeMillis();
String sqlString = "load data local infile ? into table test" ;
PreparedStatement pstmt;
try {
pstmt = connection.prepareStatement(sqlString);
pstmt.setString(1, "tfacts_result" );
pstmt.executeUpdate();
pstmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
System. out .println( "program runs " + (endTime - starTime) + "ms" );
}
public static void mysql_batch( string sqlStr, int point)
{
string sql = "insert into test(node1, node2, weight) values(?, ?, ?)" ;
Connection conn = getConn( "mysql" );
conn.setAutoCommit( false );
//clear(conn);
try
{
PreparedStatement prest = conn.prepareStatement(sql);
//long a = System.currentTimeMillis();
for ( int x = 1; x <= count; x++)
{
prest.setInt(1, x);
prest.setString(2, "张三" );
prest.addBatch();
if (x % point == 0)
{
prest.executeBatch();
conn.commit();
}
}
prest.close();
//long b = System.currentTimeMillis();
//print("MySql批量插入10万条记录", a, b, point);
}
catch (Exception ex)
{
ex.printStackTrace();
}
finally
{
close(conn);
}
|
若是要导出一个表中的部分字段或者部分符合条件的记录,须要用到了mysql的into outfile 和 load data infile。
例以下面的mysql命令是把select的mytable表中的数据导出到/home/db_bak2012文件。
1
|
select * from mytable where status!=0 and name!= '' into outfile '/home/db_bak2012' fields terminated by '|' enclosed by '"' lines terminated by '\r\n' ;
|
假如要导入刚才备份的数据,可使用load file方法,例以下面的mysql命令,把导出的数据导入了mytable_bak的表中:
1
|
load data infile '/home/db_bak2012' into table mytable_bak fields terminated by '|' enclosed by '"' lines terminated by '\r\n' ;
|
这种方法的好处是,导出的数据能够本身规定格式,而且导出的是纯数据,不存在建表信息,你能够直接导入另一个同数据库的不一样表中,相对于mysqldump比较灵活机动。
1
2
3
4
5
6
7
8
9
10
|
#基本语法:
load data [low_priority] [ local ] infile 'file_name txt' [replace | ignore]
into table tbl_name
[fields
[terminated by 't' ]
[OPTIONALLY] enclosed by '' ]
[escaped by'\' ]]
[lines terminated by 'n' ]
[ignore number lines]
[(col_name, )]
|
个人文章通常浅显易懂,不会搞那么深刻让你们很难理解。(其实我水平也不咋样)
LOAD DATA INFILE 一直被认为是MySQL很强大的一个数据导入工具,由于他速度很是的快。
不过有几个问题必定要注意
一、编码。
二、灵活导入导出。
我来举两个例子说明一下。
1、关于编码
咱们的示例文本文件:
"我爱你","20","相貌日常,常常耍流氓!哈哈"
"李奎","21","相貌日常,常常耍流氓!哈哈"
"王二米","20","相貌日常,常常耍流氓!哈哈"
"老三","24","很强"
"老四","34","XXXXX"
"老五","52","***%*¥*¥*¥*¥"
"小猫","45","中间省略。。。"
"小狗","12","就会叫"
"小妹","21","PP的很"
"小坏蛋","52","表里不一"
"上帝他爷","96","很是英俊"
"MM来了","10","。。。"
"歌颂党","20","社会主义好"
"人民好","20","的确是好"
"老高","10","学习很好"
"斜三","60","眼睛斜了"
"中华之子","100","威武的不行了"
"大米","63","我爱吃"
"苹果","15","好吃"
咱们的示例表结构:
+-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| t0 | CREATE TABLE `t0` (
`id` bigint(20) unsigned NOT NULL auto_increment,
`name` char(20) NOT NULL,
`age` tinyint(3) unsigned NOT NULL,
`description` text NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_name` (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 |
+-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
咱们把这个文本文件从WINDOWS 下COPY到LINUX下看看
mysql> load data infile '/tmp/t0.txt' ignore into table t0 character set gbk fields terminated by ',' enclosed by '"' lines terminated by '\n' (`name`,`age`,`description`);
Query OK, 19 rows affected (0.01 sec)
Records: 19 Deleted: 0 Skipped: 0 Warnings: 0
mysql> select * from t0;
+----+----------+-----+----------------------------+
| id | name | age | description |
+----+----------+-----+----------------------------+
| 1 | 我爱你 | 20 | 相貌日常,常常耍流氓!哈哈 |
| 2 | 李奎 | 21 | 相貌日常,常常耍流氓!哈哈 |
| 3 | 王二米 | 20 | 相貌日常,常常耍流氓!哈哈 |
| 4 | 老三 | 24 | 很强 |
| 5 | 老四 | 34 | XXXXX |
| 6 | 老五 | 52 | ***%*¥*¥*¥*¥ |
| 7 | 小猫 | 45 | 中间省略。。。 |
| 8 | 小狗 | 12 | 就会叫 |
| 9 | 小妹 | 21 | PP的很 |
| 10 | 小坏蛋 | 52 | 表里不一 |
| 11 | 上帝他爷 | 96 | 很是英俊 |
| 12 | MM来了 | 10 | 。。。 |
| 13 | 歌颂党 | 20 | 社会主义好 |
| 14 | 人民好 | 20 | 的确是好 |
| 15 | 老高 | 10 | 学习很好 |
| 16 | 斜三 | 60 | 眼睛斜了 |
| 17 | 中华之子 | 100 | 威武的不行了 |
| 18 | 大米 | 63 | 我爱吃 |
| 19 | 苹果 | 15 | 好吃 |
+----+----------+-----+----------------------------+
19 rows in set (0.00 sec)
我来讲明一下相关的参数
关于个人导入语句,我如今直说两个,其余的参考手册。
character set gbk;
这个字符集必定要写,要否则就会乱码或者只导入一部分数据。
ignore into table
由于name 列加了惟一索引,加这个是为了不重复数据插入报错。
加入咱们再次运行这个导入语句就会发现
Query OK, 0 rows affected (0.00 sec)
Records: 19 Deleted: 0 Skipped: 19 Warnings: 0
没有任何值导入,由于里面已经有了相同的值。
这里也能够用replace into table
MySQL会把相同的先干掉,再插入新的值。
mysql> load data infile '/tmp/t0.txt' replace into table t0 character set gbk fields terminated by ',' enclosed by '"' lines terminated by '\n' (`name`,`age`,`description`);
Query OK, 38 rows affected (0.00 sec)
Records: 19 Deleted: 19 Skipped: 0 Warnings: 0
mysql> select * from t0;
+----+----------+-----+----------------------------+
| id | name | age | description |
+----+----------+-----+----------------------------+
| 20 | 我爱你 | 20 | 相貌日常,常常耍流氓!哈哈 |
| 21 | 李奎 | 21 | 相貌日常,常常耍流氓!哈哈 |
| 22 | 王二米 | 20 | 相貌日常,常常耍流氓!哈哈 |
| 23 | 老三 | 24 | 很强 |
| 24 | 老四 | 34 | XXXXX |
| 25 | 老五 | 52 | ***%*¥*¥*¥*¥ |
| 26 | 小猫 | 45 | 中间省略。。。 |
| 27 | 小狗 | 12 | 就会叫 |
| 28 | 小妹 | 21 | PP的很 |
| 29 | 小坏蛋 | 52 | 表里不一 |
| 30 | 上帝他爷 | 96 | 很是英俊 |
| 31 | MM来了 | 10 | 。。。 |
| 32 | 歌颂党 | 20 | 社会主义好 |
| 33 | 人民好 | 20 | 的确是好 |
| 34 | 老高 | 10 | 学习很好 |
| 35 | 斜三 | 60 | 眼睛斜了 |
| 36 | 中华之子 | 100 | 威武的不行了 |
| 37 | 大米 | 63 | 我爱吃 |
| 38 | 苹果 | 15 | 好吃 |
+----+----------+-----+----------------------------+
19 rows in set (0.00 sec)
(`name`,`age`,`description`);
这些也就是具体的表属性了,指明这个就能够导入想要的数据。
二、关于灵活性,其实也就是一个记录功能
若是想在导入的时候记录一下导入的具体时间怎么办?
咱们来看看
先加一个时间属性记录导入时间。
mysql> alter table t0 add update_time timestamp not null;
Query OK, 19 rows affected (0.00 sec)
Records: 19 Duplicates: 0 Warnings: 0
干掉惟一索引
mysql> alter table t0 drop index idx_name;
Query OK, 19 rows affected (0.00 sec)
Records: 19 Duplicates: 0 Warnings: 0
mysql> load data infile '/tmp/t0.txt' into table t0 character set gbk fields terminated by ',' enclosed by '"' lines terminated by '\n' (`name`,`age`,`description`) set update_time=current_timestamp;
Query OK, 19 rows affected (0.00 sec)
Records: 19 Deleted: 0 Skipped: 0 Warnings: 0
mysql> select * from t0;
+----+----------+-----+----------------------------+---------------------+
| id | name | age | description | update_time |
+----+----------+-----+----------------------------+---------------------+
| 20 | 我爱你 | 20 | 相貌日常,常常耍流氓!哈哈 | 0000-00-00 00:00:00 |
…………
| 24 | 老四 | 34 | XXXXX | 0000-00-00 00:00:00 |
| 25 | 老五 | 52 | ***%*¥*¥*¥*¥ | 0000-00-00 00:00:00 |
…………
| 35 | 斜三 | 60 | 眼睛斜了 | 0000-00-00 00:00:00 |
| 36 | 中华之子 | 100 | 威武的不行了 | 0000-00-00 00:00:00 |
…………
| 60 | 王二米 | 20 | 相貌日常,常常耍流氓!哈哈 | 2008-06-30 14:58:37 |
…………
| 68 | 上帝他爷 | 96 | 很是英俊 | 2008-06-30 14:58:37 |
| 69 | MM来了 | 10 | 。。。 | 2008-06-30 14:58:37 |
…………
| 75 | 大米 | 63 | 我爱吃 | 2008-06-30 14:58:37 |
| 76 | 苹果 | 15 | 好吃 | 2008-06-30 14:58:37 |
+----+----------+-----+----------------------------+---------------------+
38 rows in set (0.00 sec)
新导入的19条记录时间被记录了下来。
只是以前的数据库没有记录,不过如今不须要这些重复数据了。
干掉他就能够了
mysql> alter table t0 order by id desc;
Query OK, 38 rows affected (0.01 sec)
Records: 38 Duplicates: 0 Warnings: 0
mysql> alter ignore table t0 add unique index idx_name (`name`);
Query OK, 38 rows affected (0.00 sec)
Records: 38 Duplicates: 19 Warnings: 0
mysql> alter table t0 order by id asc;
Query OK, 19 rows affected (0.01 sec)
Records: 19 Duplicates: 0 Warnings: 0
mysql> select * from t0;
+----+----------+-----+----------------------------+---------------------+
| id | name | age | description | update_time |
+----+----------+-----+----------------------------+---------------------+
| 58 | 我爱你 | 20 | 相貌日常,常常耍流氓!哈哈 | 2008-06-30 14:58:37 |
| 59 | 李奎 | 21 | 相貌日常,常常耍流氓!哈哈 | 2008-06-30 14:58:37 |
| 60 | 王二米 | 20 | 相貌日常,常常耍流氓!哈哈 | 2008-06-30 14:58:37 |
| 61 | 老三 | 24 | 很强 | 2008-06-30 14:58:37 |
| 62 | 老四 | 34 | XXXXX | 2008-06-30 14:58:37 |
| 63 | 老五 | 52 | ***%*¥*¥*¥*¥ | 2008-06-30 14:58:37 |
| 64 | 小猫 | 45 | 中间省略。。。 | 2008-06-30 14:58:37 |
| 65 | 小狗 | 12 | 就会叫 | 2008-06-30 14:58:37 |
| 66 | 小妹 | 21 | PP的很 | 2008-06-30 14:58:37 |
| 67 | 小坏蛋 | 52 | 表里不一 | 2008-06-30 14:58:37 |
| 68 | 上帝他爷 | 96 | 很是英俊 | 2008-06-30 14:58:37 |
| 69 | MM来了 | 10 | 。。。 | 2008-06-30 14:58:37 |
| 70 | 歌颂党 | 20 | 社会主义好 | 2008-06-30 14:58:37 |
| 71 | 人民好 | 20 | 的确是好 | 2008-06-30 14:58:37 |
| 72 | 老高 | 10 | 学习很好 | 2008-06-30 14:58:37 |
| 73 | 斜三 | 60 | 眼睛斜了 | 2008-06-30 14:58:37 |
| 74 | 中华之子 | 100 | 威武的不行了 | 2008-06-30 14:58:37 |
| 75 | 大米 | 63 | 我爱吃 | 2008-06-30 14:58:37 |
| 76 | 苹果 | 15 | 好吃 | 2008-06-30 14:58:37 |
+----+----------+-----+----------------------------+---------------------+
19 rows in set (0.00 sec)
如今是达到了目的了,为啥中途要干掉惟一索引呢?由于set 语法 再有IGNORE 的时候会忽略掉。
1
2
|
#用mysql导出时,若是文件目录没有权限,能够将文件导出到 mysql 库所在的服务器上的 /tmp/ 目录下(推荐<span></span>)
select * from s_reviews where stars >0 limit 10 into outfile '/tmp/reviews.csv' fields terminated by ',' optionally enclosed by '"' escaped by '"' lines terminated by '\n' ;
|
1
2
3
|
#从csv文件导入数据,导入的时候<span></span><span></span>,能够将要导入的文件先复制到 mysql 库所在的服务器上的 /tmp/ 目录下(推荐<span></span>)。
要将csv文件的字段和mysql表中的字段对应起来,以避免出错,同时也能够提醒本身导入的是哪些数据
LOAD DATA LOCAL INFILE '/tmp/reviews.csv' INTO TABLE s_reviews fields terminated by ',' optionally enclosed by '"' escaped by '"' lines terminated by '\n' (` id `, `user_id`, `user_name`, `shop_id`, `shop_name`, `arv_price`, `environment`, `taste_or_product`, `service`, `comment_type`, `comment`, `stars`, `review_time`, `fetch_time`);
|