我有一个简单的查询,返回25,026行:
MySqlCommand cmd = new MySqlCommand("SELECT ID FROM People", DB);
MySqlDataReader reader = cmd.ExecuteReader();
(ID
是int
。)如果我这样做:
int i = 0;
while (reader.Read()) i++;
i
将等于25026.但是,我需要对循环中的每个ID进行一些处理;每次迭代都会在数百毫秒内完成。
int i = 0;
MySqlCommand updater = new MySqlCommand("INSERT INTO OtherTable (...)", anotherConnection);
updater.Prepare();
while (reader.Read()) {
int id = reader.getInt32(0);
// do stuff, then
updater.ExecuteNonQuery();
i++;
}
然而,在处理大约4:15之后,reader.Read()
只返回false。在我的大多数测试运行中,i
等于14896,但它有时也会停在11920. DataReader
在相同数量的记录之后退出是可疑的,并且它在不同行数后停止的次数似乎更奇怪。
当肯定有更多行时,为什么reader.Read()
会返回false?没有例外被抛出 - 甚至没有第一次机会异常。
更新:我在回复Shaun's answer时提到,我确信MySqlDataReader.Read()
正在吞下异常,因此我下载了Connector/Net's source code({{ 1}})并将项目添加到我的解决方案中。果然,在处理6:15之后,例外!
对bzr branch lp:connectornet/6.2 C:/local/path
的调用会抛出resultSet.NextRow()
,并显示“从流中读取失败”的消息。 MySqlException
是InnerException
:
SocketException
10054表示TCP套接字已中止{ Message: "An existing connection was forcibly closed by the remote host",
ErrorCode: 10054,
SocketErrorCode: ConnectionReset }
而不是正常断开连接握手(RST
,FIN
,FIN ACK
),这告诉我一些棘手的事情正在发生到网络连接。
在my.ini中,我将ACK
和interactive_timeout
转换为1814400(秒)无效。
那么......为什么我的连接在阅读6:15(375秒)后被拆除了?
(另外,为什么在我使用官方二进制文件时会吞下这个异常?它看起来就像它应该冒泡到我的应用程序代码一样。)
答案 0 :(得分:2)
也许你有一个损坏的表 - 这个人的问题听起来与你的非常相似: http://forums.asp.net/t/1507319.aspx?PageIndex=2 - 修复表格,看看会发生什么。
如果不起作用,请继续阅读:
我的猜测是你正在遇到某种类型的死锁,特别是考虑到你正在阅读和写作。这将解释为什么它适用于简单的循环,但在您进行更新时不起作用。它也可以解释为什么它每次都在同一行/时间内发生。
SqlDataReader中有一个奇怪的错误,它阻止异常(http://support.microsoft.com/kb/316667)。在MySqlDatareader中可能有类似的东西 - 在最后的.Read()调用之后,尝试调用.NextResult()。即使它不是死锁,它也可以帮助您诊断问题。在这些类型的情况下,您希望更倾向于“信任但验证” - 是的,文档说并且异常将在时间上抛出,但有时(很少)文档存在:)对于第三方尤其如此供应商 - 例如看http://bugs.mysql.com/bug.php?id=53439 - mysql .net库有一些问题,比如你过去的问题。
另一个想法是观察数据库中正在发生的事情 - 确保在代码退出的行之前提取数据。
如果失败了,我会读取所有数据,缓存它,然后进行修改。通过批量修改,代码将更少繁琐并且执行得更快。
或者,每1000行左右重置一次阅读器(并跟踪你最近的行ID)
希望有些东西可以帮助你解决挫败感! :)
答案 1 :(得分:2)
由于我刚刚阅读int
,我最终只是将整个结果集读入List<int>
,关闭了读者,然后进行了处理。这对于int
来说是好的,因为甚至一百万的占用率高于{1}。 100 MB的RAM,但我仍然对根本问题没有得到解决感到失望 - 如果我每行读取多个int
,内存将成为大型数据集的一个非常大的问题。
答案 2 :(得分:1)
尝试设置更长的连接超时。
答案 3 :(得分:1)
有两个问题让事情变得更加混乱:
第一个,正如另一篇文章中提到的那样,旧版本的MySQL .NET连接器吞噬了超时异常。我使用的是mysql.data.dll版本6.1.x,升级到6.3.6后,异常被正确抛出。
第二个是默认的MySQL服务器超时,特别是 net_read_timeout 和 net_write_timeout (分别默认为30秒和60秒)。
对于旧版本的mysql.data.dll,当您使用datareader循环中的数据执行操作并且超过60秒的默认超时时,它将只是坐在那里而不做任何事情。对于较新的版本,它会正确地抛出超时异常,这有助于诊断问题。
希望这可以帮助某人,因为我偶然发现了这一点,但解决方案是使用不同的方法,而不是实际原因/修复。
TLDR :my.ini中的mysql服务器上的修复增加了 net_read_timeout 和 net_write_timeout ,尽管升级mysql.data.dll是一个好主意。
答案 4 :(得分:0)
可能这是服务器端的超时?
答案 5 :(得分:0)
尝试在MySqlCommand上设置超时,而不是在“cmd”和“updater”上设置MySqlConnection。
如果您执行以下操作会发生什么:SELECT TOP 100 ID FROM PEOPLE
?
答案 6 :(得分:0)
试试这个 1.添加参考System.Transactions;
using(TransactionScope scope = new TransactionScope())
{
//Initialize connection
// execute command
:
:
scope.Complete();
}
使用Scope编写整个插入/更新逻辑。这肯定会帮助你。
答案 7 :(得分:0)
创建命令后添加以下内容。
cmd.CommandTimeout = 0;
这会将CommandTimeout设置为无限期。您获得超时的原因可能是因为执行的连接仍处于“命令”阶段,因为Reader。
尝试设置CommandTimeout = 0或首先读取所有内容,然后对结果执行后续功能。否则,我唯一可能看到的另一个问题是,由于服务器本身超时,Sql Server正在针对指定的进程ID丢弃结果集。
答案 8 :(得分:0)
这个家伙所经历的是类似的东西:在读取同一记录的过程中,在完全相同的时刻挂上了Read方法(这与我猜的相同)。 在他的情况下,他在Read()循环期间调用另一个web服务,并且一个超时导致Read()挂起而没有异常。
在你的机器上是否可以相同,Read()循环中的更新超时(我认为更新使用默认的30秒超时)并产生相同的效果?
也许是一个长镜头,但读这两个故事听起来很多人。