從數據庫里面下載一百萬條數據 導入CSV文件里面出現這種錯誤

進行如下修改 打開 my.ini 修改 將max_allowed_packet改大
但是這些並不能解決根原問題,在寫函數的時候 要及時的銷毀 不用的變量, 對變量盡量用引用
如:
除此之外還要分配
原來是php.ini中的內存分配的問題,默認php代碼能夠申請到的最大內存字節數就是134217728 bytes,如果代碼執行的時候再需要更多的內存,就會報錯了,於是就將php.ini文件中的配置改了一下
form:http://www.jb51.net/article/57237.htm
這是更詳細的
背景
這個問題由一個同事問到的一次導入數據引發。一個很常見的操作,將數據從一個表中dump出來,在用mysql < a.sql的方式導入到另一個庫的一個表中。
在執行導入的時候,提示 MySQL server has gone away。在追查的時候突然想到會不會是因為max_allowed_packet太小導致的。將max_allowed_packet改大,確實解決了問題。
(史平忠的方法是修改my.ini 的 max_allowed_packet 為 20M,然后重啟mysql服務器,問題解決)
本文基於在此之后想到的兩個問題:
1、 MySQL server has gone away這個提示很不友好,是不是所有的包超過大小都是報這個?
2、 對於出現這種不友好的錯誤提示,有什么方法定位原因(而不是靠“突然想到”)?
追查1
步驟:a) 把max_allowed_packet設置為一個比較小的值, set global max_allowed_packet=16384
b) 寫一個簡單的語句 insert into tb values(xxx),(xxx),(xxx)……(xxx) 讓這個文件足夠大,比如我測試使用 a.sql大小為37318
c) 執行導入語句,提示 ER2ROR 1153 (08S01) at line 1: Got a packet bigger than ‘max_allowed_packet’ bytes
初步結論是並不是所有的語句太大都會導致直接顯示gone away。如果都是后面這個提示就好了,一目了然,用戶自然會去修改max_allowed_packet。
因此我們的問題就變成:為什么會有不同的提示?
分析1
我們將報gone away的稱為場景1,另外一個稱為場景2.
場景1執行的sql語句大小是16554913
實際上場景2的返回信息是由MySQL服務端返回的,因為服務端才能判斷得到包大小超過。那么場景1為什么不是相同的提示呢?是不是壓根兒請求就沒有發到服務端?
照這個思路查到下面代碼(clent/mysql.cc)
其中場景1執行到2785行return了,而場景2是在調用2786行的put_error中輸出上述信息的。
這證實了上面的結論,場景1是在調用請求的時候提示的失敗,還沒有到服務端判斷包大小的環節。但是問題又來了,發送失敗為什么要提示gone away呢?我們最常見到的gone away,是執行期間MySQL重啟了,但這個case里面mysql並沒有重啟(這個很容易確認)。
分析1-2
進到mysql_real_query里面看看。發現執行路徑差別在此(sql-common/client.c)
場 景1調用net_write_command失敗,會執行到行854,場景2調用成功。就是說場景2里面,整個語句是都發給服務端成功的,因此服務端可以 做后續的判斷(包大小)。而場景1由於發命令失敗,執行到mysql_reconnect.。但進入mysql_reconnect發現沒有必要重發(我 們是普通的客戶端),然后發現一處hard code。
這里就是罪魁禍首了。因為mysql->reconnect為空,說明這里不需要重新連接。於是就直接在set_mysql_error中傳入 CR_SERVER_GONE_ERROR, 輸出在客戶端就是gone away。
至於為什么場景1發送會失敗,關鍵就是內容太大,tcp都不讓它發了(write調用失敗)
追查2
其實筆者覺得這個問題反而比較有意義,gone away這種錯誤提示不友好,會導致追查很難下手。有一個固定的步驟來查,避免抓瞎。
從上面的分析知道,由於之前的調用失敗,客戶端試圖進行“重連”,但是由於mysql->reconnect為0導致返回gone away。可以從這里下手。獲取在執行mysql_reconnect之前的那個錯誤號。
一個debug命令文件
[dingqi.lxb@rds064076 master]$ cat x.debug
set args -Srun/mysql.sock -uroot test < b.sql
b mysql_reconnect
r
c
f 1
p mysql->net.last_errno
在shell執行 gdb mysql -x x.debug
$1 = 1160
這個1160就是我們要的了,
./include/mysqld_ername.h:{ “ER_NET_ERROR_ON_WRITE”, 1160, “Got an error writing communication packets” },
表明了真正的錯誤是交互時發包失敗。
小結
都是包太大,只是一個大過頭了,導致在失敗在客戶端發生,又由於重連時的hard code,導致了一個不友好的提示 gone away。
神馬?你也碰到這種情況但不是max_allowed_packet 的問題,但是你的mysql沒有debug信息?載一個源碼安裝。或者可以將你的復現步驟發給我。#異常gone away收集中#
原創文章,轉載請注明: 文章地址MySQL數據庫關於一次導入數據提示的MySQL server has gone away



