mysql快速插入/更新大量記錄


最近的項目中需要將幾個dump文件(文本格式、1~2G)的記錄導入到mysql數據庫中,由於數據量比較大(幾百萬、上千萬條記錄),有插入記錄,也有更新記錄的,導致插入\更新速度比較慢。

一開始,將單條sql語句交給mysql執行,測試下來,最快一次也要一個半小時。於是想辦法改進之。

 

(1)針對插入記錄,使用sql語句一次插入多條記錄。實例:

INSERT INTO tbl_name (a,b,c) VALUES(1,2,3),(4,5,6),(7,8,9);

具體參見sql語法:

http://dev.mysql.com/doc/refman/5.0/en/insert.html

 

在程序中,使用循環拼接sql語句,然后一次性丟給myql_query()處理即可。

需要注意的是,sql語句不是越長越好,太長了可能會超出mysql限制(聽同事介紹,mysql的限制是63M)。

我在實測中,我限制sql長度在10M:

 1 for(...)
 2 {
 3     m_strSQL += ...;
 4 
 5     if (m_strSQL.length() > 10485760) //10M
 6     {
 7          m_pMysqlStatement->execute(m_strSQL.substr(0, m_strSQL.length() - 1));
 8          m_strSQL= "INSERT INTO location (locationid, name, alternatename) VALUES ";
 9     }
10 
11 }

測試結果為:

8267787條記錄,耗時754秒(數據庫在局域網內的不同機器上),基本滿足要求。

 

(2)對於更新記錄,由於update語法不支持一次更新多條記錄,無法使用類似“INSERT INTO tbl_name (a,b,c) VALUES(1,2,3),(4,5,6),(7,8,9);”的形式進行更新,只能拼接多條sql語句一起更新:

update location set languages = 'zh' where locationid = '12344';update location set postalcode = '14343' where locationid = '3455';

但是這樣一來,問題出現了:

(I)在連接數據庫時需要啟用multi-query支持,允許一次執行多條sql語句。參見:http://www.cnblogs.com/chutianyao/archive/2011/11/07/2239464.html

(II)還需要處理resultset的釋放問題,否則mysql會報錯:"Commands out of sync; you can't run this command now"

(III)針對update語句,雖然並沒有resultset返回,但仍然需要釋放。而由於未知原因(可能是sql語句太長?),釋放resultset非常耗時,最終算下來得不償失。

 

綜合以上情況,同事提出了另一種解決方法:針對更新記錄,仍然使用insert語句,不過限制主鍵重復時,更新字段。如下:

INSERT INTO location (locationid, languages) VALUES('13243', 'zh'),VALUES('13244', 'en') ON DUPLICATE KEY UPDATE languages=VALUES(languages)

但是這樣又引出了另外一個問題:在一條sql語句中只能更新某些指定的字段,而程序中可能會有不同的更新條件。比如:上一條記錄更新languages字段,而下一條記錄則更新postalcode字段,這樣是沒辦法蟹島一條sql語句中的。

解決辦法是:針對這兩個不同的字段,使用不同的sql語句,保證每個sql語句只更新某個字段:

 1 for(...)
 2 {
 3     m_strSQL_Language +=...
 4     m_strSQL_Postcode +=...
 5     if (m_strSQL_Language.length() > 10485760) //10M
 6     {
 7         m_strSQL_Language.erase(m_strSQL_Language.length() - 1);
 8         m_strSQL_Language += " ON DUPLICATE KEY UPDATE languages=VALUES(languages)";
 9         m_pMysqlStatement->execute(m_strSQL_Language);
10 
11         m_strSQL_Language = "INSERT INTO location (locationid, languages) VALUES ";
12     }
13 
14     if (m_strSQL_Postcode.length() > 10485760) //10M
15     {
16         m_strSQL_Postcode.erase(m_strSQL_Alternate_Postcode.length() - 1);
17         m_strSQL_Postcode += " ON DUPLICATE KEY UPDATE postalcode=VALUES(postalcode)";
18         m_pMysqlStatement->execute(m_strSQL_Postcode);
19 
20         m_strSQL_Postcode = "INSERT INTO location (locationid, postalcode) VALUES ";
21     }
22 }

問題得到了完美解決。

 

 

 

 

 

 

 

 

 

 


免責聲明!

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



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