【技術筆記】Npgsql 的 CommandTimeout 預設為 30 秒:大量資料查詢失敗的原因竟然是這個
Copyright Notice: This article is an original work licensed under the CC 4.0 BY-NC-ND license.
If you wish to repost this article, please include the original source link and this copyright notice.
Source link: https://v2know.com/article/1151
最近在開發一個工具,從 PostgreSQL 匯出大量資料為 CSV。功能本身很單純,平時匯出幾百筆資料沒問題,但當資料筆數上升到幾萬筆時,程式卻開始失敗,並在中途中斷。
初期無法得知錯誤具體原因,只知道程式落入了 catch (Exception)
分支。經過一番調查與錯誤記錄強化,最終找到關鍵錯誤訊息:
Exception while reading from stream
---> System.TimeoutException: Timeout during reading attempt
這個訊息揭示了一個不容易注意的關鍵點:
Npgsql 的
CommandTimeout
預設值為 30 秒。
也就是說,當查詢執行與讀取結果的整體耗時超過 30 秒時,Npgsql 會主動取消操作,並拋出 TimeoutException。
什麼是 CommandTimeout?
CommandTimeout
是 Npgsql 的一個屬性,控制每條 SQL 指令允許執行與讀取結果的最長時間。預設值為 30 秒。
這個限制在多數情況下不會造成問題,但當:
-
查詢本身較為複雜(例如使用多表 JOIN、排序、ROW_NUMBER 等)
-
資料筆數較多
-
匯出流程每次查詢一部分資料(分頁)
這些因素疊加起來,很容易讓單次查詢時間超過 30 秒,導致操作被中斷。
解法:明確設定較長的逾時時間
要解決這個問題,只需要在連線字串中加入:
Command Timeout=300;
這表示允許單一 SQL 指令最多執行 300 秒(5 分鐘),就能有效避免逾時錯誤。
範例設定:
{
"ConnectionStrings": {
"PostgresLocal": "Host=localhost;Port=5432;Username=admin;Password=admin;Database=exampledb;Command Timeout=300;"
}
}
若你的程式會動態產生連線字串,也可以用 NpgsqlConnectionStringBuilder
來設定:
var builder = new NpgsqlConnectionStringBuilder(baseConn)
{
CommandTimeout = 300
};
var conn = new NpgsqlConnection(builder.ConnectionString);
額外提醒:CommandTimeout ≠ ConnectionTimeout
-
CommandTimeout
:控制單一指令(查詢 + 讀取結果)的最大等待時間,預設 30 秒 -
ConnectionTimeout
:控制建立連線所需的最大時間,預設 15 秒
兩者常被混淆,但用途與風險完全不同。
小結
這次經驗讓我牢記一件事:
Npgsql 的
CommandTimeout
預設是 30 秒,若未手動設定,查詢量大時極易觸發 TimeoutException。
實務上,建議針對批次查詢、匯出等場景都明確設定一個足夠的 CommandTimeout
,避免程式在資料量變大時才暴露問題。
如你也遇到類似 PostgreSQL 匯出逾時問題,希望這篇筆記對你有所幫助。若你對進一步優化匯出效能(例如 COPY TO STDOUT
)有興趣,也歡迎留言討論。
This article was last edited at