首先MySQL8號稱性能是mysql5的2倍以上,并且一直聽講單表500萬數據是一個瓶頸,那么我打算在最新版的mysql上導入一個1000萬數據,驗證看看mysql對于單表大數據的表現情況。
mysql數據導入測試
環境準備
- 在虛擬機中安裝好mysql8.0.17,存儲引擎選擇innoDB,并新增一個study數據庫,并創建t_user表,為簡單起見,就2個字段,id和name;為減少網絡可能存在問題,執行的sql放到本地執行。不需要建立索引,畢竟導入大數據,有索引的話,還需而外維護,那性能更慢。
create table t_user(id int, name varchar(20));
- 虛擬機配置調整,為充分使用虛擬機的性能,調整虛機配置,4個cpu,4g內存,10g的數據盤。
由于硬盤是固態盤,相信更多的瓶頸在cpu和內存。限于配置,也只能評估個大概耗時。
生成sql測試文件
拼這個sql很簡單,隨便用什么語言,只要生產sql文件就行,單條的語句為:
insert into t_user values('1','程序不就是0和1');
這里我使用JAVA來生成sql文件,1000萬數據大概花了45秒左右,實現代碼截圖參考圖1,結果參考圖2
圖1:生成sql文件
圖2:1千萬條數據
這個文本文件比較大,在mac上有580多M,光打開都要花一定的時間,所以可以想象,如果通過遠程方法導入,對網絡延時要求肯定很高。
方案1:存儲過程導入
先來看看存儲過程導入千萬條數據耗時,存過就不需要文件了,直接在過程體中循環拼接insert語句即可。代碼如下:
begin DECLARE v_i int unsigned DEFAULT 0; WHILE v_i < 10000000 DO insert into t_user values(v_i,'程序不就是0和1'); SET v_i = v_i+1; END WHILE;
存儲過程耗時
總耗時大約3個小時3分鐘,還是比較慢的。
方案2:用mysql命令導入
mysql命令是mysql自帶的命令,位于bin目錄下,該命令比較簡單,為了避免網絡延遲,我們先把用java生成的sql文件傳到服務器上,使用rz命令進行上傳到mysql的bin目錄下,這樣執行命令稍微簡單點,輸入用戶名和密碼即可執行。
這里有個地方需要注意下:因為sql文件較大,默認的話會報一個錯誤:ERROR 2006 (HY000): MySQL server has gone away,意思是記錄數超過最大值。我們可以更改全局變量,只在本次mysql進程中有效,重啟mysql就失效了,如果想一直生效,可以在my.cnf中配置。更改后,就可以執行導入命令了。
set global max_allowed_packet=1024*1024*1000;##設置為1G
上傳sql文件到服務器
./mysql -uroot -p study1 < t_user.sql
總共耗時大約3小時8分鐘,跟第一種方案區別不大。總結一下,對于大批量數據基本不能使用insert into 的方案,改用文本導入方案。所以我們重新生成數據文件。java代碼更改如下:
使用制表符號作為數據分隔符,方便下面命令使用。
方案3:用mysqlimport命令導入
mysql從安全考慮,默認對這種導入文件的方式是關閉的,可以用該命令查詢:
show variables like 'local_infile';
在全局環境中打開可以使用命令:
set global local_infile=ON;
如過沒有打開此參數,而執行了mysqlimport命令會收到一個報錯:ERROR 1148 (42000): The used command is not allowed with this MySQL version。
mysqlimport命令的常用參數介紹:
- --fields-terminated-by=字符串:設置字段間的分隔符,可以為單個或多個字符。默認值為制表符“t”,這就是上述我們生成文件時候故意使用制表符。
- -L, --local:表示從客戶端任意路徑讀取文件導入表中,未設置該選項時,默認只從datadir下同名數據庫目錄下讀取文件導入。
- -p, --password[=name]:指定用戶密碼。
- -u, --user=name:指定登入MySQL用戶名。
我們現在執行下面命令執行導入:
./mysqlimport -uroot -p --local study2 t_user.txt
備注:
- 上面重新生成的數據文件(t_user.txt),同樣先上傳服務器。
- 文件名默認就是要導入的表名。
- 耗時大約1分18秒。
mysqlimport其實是load data infile 的命令行工具,理論講它們速度應該是一樣的,所以就不再演示load data infile 命令了。
數據有了,看看查詢效率
因為默認沒有索引,所以隨便查一個數據,大約耗時14秒。
select * from t_user where id = 1
加上索引之后,耗時幾乎為0。忽略不計
可見千萬的單表數據在走索引情況下,mysql其實還是可以扛住的。
總結
直接看圖吧
基本上在大數據導入的情況下,mysqlimport命令耗時可以忽略不計了。只不過使用該命令需要打開local_infile參數。