[整理]MySql批量数据导入Load data infile解决方案
有時(shí)候我們需要將大量數(shù)據(jù)批量寫(xiě)入數(shù)據(jù)庫(kù),直接使用程序語(yǔ)言和Sql寫(xiě)入往往很耗時(shí)間,其中有一種方案就是使用MySql Load data infile導(dǎo)入文件的形式導(dǎo)入數(shù)據(jù),這樣可大大縮短數(shù)據(jù)導(dǎo)入時(shí)間。
假如是從MySql客戶端調(diào)用,將客戶端的文件導(dǎo)入,則需要使用 load local data infile.
LOAD DATA INFILE 語(yǔ)句以很高的速度從一個(gè)文本文件中讀取行到一個(gè)表中。文件名必須是一個(gè)文字字符串。
1,開(kāi)啟load local data infile.
假如是Linux下編譯安裝,
如果使用源碼編譯的MySQL,在configure的時(shí)候,需要添加參數(shù):--enable-local-infile 客戶端和服務(wù)器端都需要,否則不能使用local參數(shù)。
./configure --prefix=/usr/local/mysql --enable-local-infile
make install
若是其它系統(tǒng),可在配置文件中配置:
在MySql 配置文件My.ini文件中下面項(xiàng)中加入local-infile=1:
add:
[mysqld]
local-infile=1
[mysql]
local-infile=1
客戶端和服務(wù)端度需要開(kāi)啟,對(duì)于客戶端也可以在執(zhí)行命中加上--local-infile=1 參數(shù):
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, 編碼格式注意:
若包含中文,請(qǐng)保證導(dǎo)入文件、連接字符串、導(dǎo)入表都是UTF-8編碼。
3,執(zhí)行
在使用LOAD DATA到MySQL的時(shí)候,有2種情況:
(1)在遠(yuǎn)程客戶端(需要添加選項(xiàng):--local-infile=1)導(dǎo)入遠(yuǎn)程客戶端文本到MySQL,需指定LOCAL(默認(rèn)就是ignore),加ignore選項(xiàng)會(huì)放棄數(shù)據(jù),加replace選項(xiàng)會(huì)更新數(shù)據(jù),都不會(huì)出現(xiàn)唯一性約束問(wèn)題。
[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)在本地服務(wù)器導(dǎo)入本地服務(wù)器文本到MySQL,不指定LOACL,出現(xiàn)唯一性約束沖突,會(huì)失敗回滾,數(shù)據(jù)導(dǎo)入不進(jìn)去,這個(gè)時(shí)候就需要加ignore或者replace來(lái)導(dǎo)入數(shù)據(jù)。
mysql>LOAD DATA INFILE '/home/zhuxu/1.txt' INTO TABLE tmp_loaddata FIELDS TERMINATED BY ',';
4,事務(wù)分析
步驟是這樣的:
1,開(kāi)啟binlog,設(shè)置binlog_format=row,執(zhí)行reset master;
2,load data infile xxxxx;
3,查看binlog。
可以看出,總共是一個(gè)事務(wù),也通過(guò)mysqlbinlog查看了binary log,確認(rèn)中間是被拆分成了多個(gè)insert形式。所以load data infile基本上是這樣執(zhí)行的:
begin
insert into values(),(),(),()...
insert into values(),(),(),()...
insert into values(),(),(),()...
...
...
commit
當(dāng)然,由于row格式的binlog的語(yǔ)句并不是很明顯的記錄成多值insert語(yǔ)句,它的格式時(shí)
insert into table
set @1=
set @2=
...
set @n=
insert into table
set @1=
set @2=
...
set @n=
insert ...
;注意這里有一個(gè)分號(hào)‘;’,其實(shí)前面這一部分就相當(dāng)于前面說(shuō)的多值insert形式
然后接下來(lái)就重復(fù)上面的那種格式,也就是一個(gè)load data infile 拆成了多個(gè)多值insert語(yǔ)句。
前面說(shuō)的是row格式記錄的load data infile,那么對(duì)于statement是怎么樣的呢?statement格式的binlog,它是這樣記錄的,binlog中還是同樣的load data語(yǔ)句,但是在記錄load data 語(yǔ)句之前,它會(huì)先將你master上這個(gè)load data 使用到的csv格式的文件拆分成多個(gè)部分,然后傳到slave上(在mysql的tmpdir下),當(dāng)然傳這些csv格式的文件也會(huì)記錄binlog event,然后最后真正的SQL語(yǔ)句形式就是load data local infile '/tmp/SQL_X_Y'這種形式(這里假設(shè)mysql的tmpdir是默認(rèn)的/tmp),實(shí)際上這樣很危險(xiǎn),比如tmpdir空間不夠,那就會(huì)報(bào)錯(cuò)。不過(guò)從效率上來(lái)說(shuō)兩者可能差不多,因?yàn)閟tatement格式的binlog也是拆分成了多個(gè)語(yǔ)句。
附:
(1)load data infile 和 load local data infile 在 innodb和MyISAM 同步方面的區(qū)別
對(duì)MyISAM引擎:
(1)對(duì)master服務(wù)器進(jìn)行 ‘load’ 操作,
(2)在master上所操作的load.txt文件,會(huì)同步傳輸?shù)絪lave上,并在tmp_dir 目錄下生成 load.txt文件
master服務(wù)器插入了多少,就傳給slave多少
(3)當(dāng)master上的load操作完成后,傳給slave的文件也結(jié)束時(shí),
即:在slave上生成完整的 load.txt文件
此時(shí),slave才開(kāi)始從 load.txt 讀取數(shù)據(jù),并將數(shù)據(jù)插入到本地的表中
對(duì)innodb引擎:
(1)主數(shù)據(jù)庫(kù)進(jìn)行 ‘Load’ 操作
(2)主數(shù)據(jù)庫(kù)操作完成后,才開(kāi)始向slave傳輸 load.txt文件,
slave接受文件,并在 tmp_dir 目錄下生成 load.txt 文件
接受并生成完整的load.txt 后,才開(kāi)始讀取該文件,并將數(shù)據(jù)插入到本地表中
異常情況處理:
1)對(duì)MyISAM引擎
當(dāng)數(shù)據(jù)庫(kù)執(zhí)行l(wèi)oad,此時(shí)如果中斷:
Slave端將報(bào)錯(cuò),例如:
####################################################################
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服務(wù)器上:
(1) 使用提示的load命令,將主服務(wù)器傳輸過(guò)來(lái)的load文件,在從服務(wù)器上執(zhí)行
(2)讓從服務(wù)器跳過(guò)錯(cuò)誤。set global sql_slave_skip_counter=1;
(3)開(kāi)啟同步
2)對(duì)Innodb引擎
由于innodb是事務(wù)型的,所以會(huì)把load文件的整個(gè)操作當(dāng)作一個(gè)事務(wù)來(lái)處理,
中途中斷l(xiāng)oad操作,會(huì)導(dǎo)致回滾。
與此相關(guān)的一些參數(shù):
max_binlog_cache_size----能夠使用的最大cache內(nèi)存大小。
當(dāng)執(zhí)行多語(yǔ)句事務(wù)時(shí),max_binlog_cache_size如果不夠大,
系統(tǒng)可能會(huì)報(bào)出“Multi-statement
transaction required more than 'max_binlog_cache_size' bytes of storage”的錯(cuò)誤。
備注:以load data 來(lái)說(shuō),如果load的文件大小為512M,在執(zhí)行l(wèi)oad 的過(guò)程中,
所有產(chǎn)生的binlog會(huì)先寫(xiě)入binlog_cache_size,直到load data 的操作結(jié)束后,
最后,再由binlog_cache_size 寫(xiě)入二進(jìn)制日志,如mysql-bin.0000008等。
所以此參數(shù)的大小必須大于所要load 的文件的大小,或者當(dāng)前所要進(jìn)行的事務(wù)操作的大小。
max_binlog_size------------Binlog最大值,一般設(shè)置為512M或1GB,但不能超過(guò)1GB。
該設(shè)置并不能?chē)?yán)格控制Binlog的大小,尤其是Binlog遇到一根比較大事務(wù)時(shí),
為了保證事務(wù)的完整性,不可能做切換日志的動(dòng)作,只能將該事務(wù)的所有SQL都記錄進(jìn)
當(dāng)前日志,直到事務(wù)結(jié)束
備注:有時(shí)能看到,binlog生成的大小,超過(guò)了設(shè)定的1G。這就是因?yàn)閕nnodb某個(gè)事務(wù)的操作比較大,
不能做切換日志操作,就全部寫(xiě)入當(dāng)前日志,直到事務(wù)結(jié)束。
(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萬(wàn)條記錄", a, b, point);
}
catch (Exception ex)
{
ex.printStackTrace();
}
finally
{
close(conn);
}
引用:
http://blog.csdn.net/zbszhangbosen/article/details/7947991
http://www.cnblogs.com/zeroone/archive/2013/05/06/3062488.html
轉(zhuǎn)載于:https://blog.51cto.com/babyhe/1310602
總結(jié)
以上是生活随笔為你收集整理的[整理]MySql批量数据导入Load data infile解决方案的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Android ContentProvi
- 下一篇: 字符串截取函数