有時候咱們須要將大量數據批量寫入數據庫,直接使用程序語言和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`);
|