mysql大批量插入數據的正確做法


MySQL插入已知的1000萬條數據

如何快速的向數據庫中插入已知的1000萬條數據

​ 假設這1000W條數據在同一個集合里,那么將這個集合進行遍歷,循環1000W次,結合數據庫編程技術,如JDBC,就可以插入數據庫,這么簡單的操作,顯然不是正確答案…

這樣做的缺陷:

1.應用服務器(程序運行所在服務器)與MySQL數據庫服務器並不是同一台,當需要執行數據庫操作時,會由應用服務器將SQL語句發送到MySQL數據庫服務器,發送過程中就需要建立網絡連接,才可以發送SQL語句,則總共需要連接1000W次,效率極低。同時,每次執行SQL語句之前,MySQL服務器還會對SQL語句進行語法分析,語義分析,編譯檢查等才可以執行,假設最終有1000W條SQL語句,則這些過程需要耗費大量時間。
針對這個缺陷,可以使用【批處理】解決,減少連接數據庫的次數,同時將單條插入語句改為一次插入多條數據以提高效率。如:

List<User> list = findAllUser();
Statement stat = conn.createStatement();
for (User u : list) {
	String sql = "INSERT INTO t_user (uname,age,email) VALUE ('"
                  +u.getUsername()+"',"+u.getAge()+",'"+u.getEmail()+"')";
	stat.addBatch(sql);
}

stat.executeBatch();
INSERT INTO t_user
      (uname,upwd,age,email)
VALUE 
      ('root1','123456',15,'root111@qq.com'),

      ('root2','123456',18,'root222@qq.com')('root3','123456',26,'root333@qq.com')....

​ 當兩種方法配合使用,可以使用每條SQL語句插入100條數據,批處理每次發送1000條這樣的數據,共循環100次即可。
​ 理論上來說,批處理操作不建議一次性超過【5000】,每條SQL語句根據具體需求調整,不建議超過【100】,可以調整循環次數來改善效率。

下面為測試代碼:

1.測試普通插入

@Test

public void testInsert() {

	UserDAO dao = new UserDAO();
	long t1 = System.currentTimeMillis();

	for(int i=0;i<10000000;i++) {

	    dao.insert(


                "INSERT INTO t_user (uname,pwd,age,email) VALUES ('root','123',15,'root@qq.com')");

	}
	long t2 = System.currentTimeMillis();
	int time = (int) ((t2-t1)/1000);
	System.out.println("共耗時:" + time +"秒")
}

測試結果:

2.測試批處理配合拼接SQL語句插入

@Test



public void testBatch() throws SQLException {
	Connection conn = DBUtils.getConn();
	Statement stat = conn.createStatement();
long t1 = System.currentTimeMillis();

	for(int k=0;k<100;k++) {
	for (int i=0;i<1000;i++) {
			StringBuilder sql =new StringBuilder();
			sql.append("INSERT INTO t_user (uname,pwd,age,email) VALUES ");
			for (int j = 0; j < 100; j++) {				sql.append("('root','123',15,'root@qq.com'),");

			}
			stat.addBatch(sql.toString().substring(0,sql.lastIndexOf(",")))
		}

		stat.executeBatch();
	}

	long t2 = System.currentTimeMillis();
	int time = (int) ((t2-t1)/1000);
	System.out.println("共耗時:" + time +"秒");

}

測試結果:
img

結果顯而易見了:第二種方案的執行效率遠高於普通插入方法,不過,具體運行時間和電腦配置應該也有關系的,所以不用糾結時間長短,還是會用高效的方法就好了。

PS:【怎么就顯而易見了,你壓根沒有貼圖啊,想知道為什么嗎,講話兒了,我自認為I7的處理器也還拿得出手,可是第一種實在是太慢了,一晚上大概四個多小時吧,只插了50W+條,對,你沒有看錯,我掐指一算,這要真插完,要八百多個小時,顯然是不成立的,肯定哪里算錯了,實際上一兩天也就沒有問題了,存儲引擎還是【InnoDB】的,以后有機會我測試下具體時間再上圖,具體細節,以后慢慢更新,感覺有點心疼我電腦,都燙手了…】

​ 在嘗試了幾次,都被各種意外打斷之后,我決定沒有必要把數據全部插完,因為實在是太多了,不多說,上圖吧

在這里插入圖片描述

測試方式我調整了一下,每10W條數據顯示一次用時,結果也算是情理之中,每10W條大概是一個小時多一點(68分鍾),這樣算下來,1000W條總共需要將近五天的時間,估計最慢也就這個樣子了,但是不理解的是,這次測試的是i3的電腦,8G內存,200多萬的時候,因為OOM,程序中斷了,但和i7的運行時間感覺沒有差多少,難道服務器的CPU性能不影響么…存疑。

來補一下之前的窟窿,據說【i3】CPU的單核性能是非常強勁的,那也就意味着,單線程的情況下,【i3】和【i7】確實沒多大區別,畢竟我也沒有用線程搞插入,如果真有這種操作,可能會體現出多核CPU的強大之處吧,對硬件不太了解,大佬們,輕點噴!

MySQL

如何快速的向數據庫中插入已知的1000萬條數據

​ 假設這1000W條數據在同一個集合里,那么將這個集合進行遍歷,循環1000W次,結合數據庫編程技術,如JDBC,就可以插入數據庫,這么簡單的操作,顯然不是正確答案…

這樣做的缺陷:

1.應用服務器(程序運行所在服務器)與MySQL數據庫服務器並不是同一台,當需要執行數據庫操作時,會由應用服務器將SQL語句發送到MySQL數據庫服務器,發送過程中就需要建立網絡連接,才可以發送SQL語句,則總共需要連接1000W次,效率極低。同時,每次執行SQL語句之前,MySQL服務器還會對SQL語句進行語法分析,語義分析,編譯檢查等才可以執行,假設最終有1000W條SQL語句,則這些過程需要耗費大量時間。
針對這個缺陷,可以使用【批處理】解決,減少連接數據庫的次數,同時將單條插入語句改為一次插入多條數據以提高效率。如:

List<User> list = findAllUser();
Statement stat = conn.createStatement();
for (User u : list) {
	String sql = "INSERT INTO t_user (uname,age,email) VALUE ('"

                    +u.getUsername()+"',"+u.getAge()+",'"+u.getEmail()+"')";
	stat.addBatch(sql);
}



stat.executeBatch();
INSERT INTO t_user
      (uname,upwd,age,email)
VALUE 
      ('root1','123456',15,'root111@qq.com'),
      ('root2','123456',18,'root222@qq.com')('root3','123456',26,'root333@qq.com')..

​ 當兩種方法配合使用,可以使用每條SQL語句插入100條數據,批處理每次發送1000條這樣的數據,共循環100次即可。
​ 理論上來說,批處理操作不建議一次性超過【5000】,每條SQL語句根據具體需求調整,不建議超過【100】,可以調整循環次數來改善效率。

下面為測試代碼:

1.測試普通插入

@Test

public void testInsert() {

	UserDAO dao = new UserDAO();
	long t1 = System.currentTimeMillis();
	for(int i=0;i<10000000;i++) {
	    dao.insert(
                "INSERT INTO t_user (uname,pwd,age,email) VALUES ('root','123',15,'root@qq.com')");
	}
	long t2 = System.currentTimeMillis();
	int time = (int) ((t2-t1)/1000);
	System.out.println("共耗時:" + time +"秒");
}

測試結果:

2.測試批處理配合拼接SQL語句插入

@Test



public void testBatch() throws SQLException {

	Connection conn = DBUtils.getConn();
	Statement stat = conn.createStatement();
	long t1 = System.currentTimeMillis();
	for(int k=0;k<100;k++) {
		for (int i=0;i<1000;i++) {

			StringBuilder sql =new StringBuilder();

			sql.append("INSERT INTO t_user (uname,pwd,age,email) VALUES ");

			for (int j = 0; j < 100; j++) {
				sql.append("('root','123',15,'root@qq.com'),");


			}
			stat.addBatch(sql.toString().substring(0,sql.lastIndexOf(",")));
		}
		stat.executeBatch();
	}
	long t2 = System.currentTimeMillis();
	int time = (int) ((t2-t1)/1000);
	System.out.println("共耗時:" + time +"秒");
}

測試結果:
img

結果顯而易見了:第二種方案的執行效率遠高於普通插入方法,不過,具體運行時間和電腦配置應該也有關系的,所以不用糾結時間長短,還是會用高效的方法就好了。

PS:【怎么就顯而易見了,你壓根沒有貼圖啊,想知道為什么嗎,講話兒了,我自認為I7的處理器也還拿得出手,可是第一種實在是太慢了,一晚上大概四個多小時吧,只插了50W+條,對,你沒有看錯,我掐指一算,這要真插完,要八百多個小時,顯然是不成立的,肯定哪里算錯了,實際上一兩天也就沒有問題了,存儲引擎還是【InnoDB】的,以后有機會我測試下具體時間再上圖,具體細節,以后慢慢更新,感覺有點心疼我電腦,都燙手了…】

​ 在嘗試了幾次,都被各種意外打斷之后,我決定沒有必要把數據全部插完,因為實在是太多了,不多說,上圖吧

在這里插入圖片描述

測試方式我調整了一下,每10W條數據顯示一次用時,結果也算是情理之中,每10W條大概是一個小時多一點(68分鍾),這樣算下來,1000W條總共需要將近五天的時間,估計最慢也就這個樣子了,但是不理解的是,這次測試的是i3的電腦,8G內存,200多萬的時候,因為OOM,程序中斷了,但和i7的運行時間感覺沒有差多少,難道服務器的CPU性能不影響么…存疑。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM