我想了解 MySqlDataReader(或一般的 IDataReader)的怪癖。在互联网上进行研究时,我发现了很多关于如何使用 MySqlDataReader 的资源,但很少了解幕后发生的事情。我问是因为我发现在某些基准测试中,我执行 MySqlCommand.ExecuteReader()
所需的时间比使用 MySqlDataReader.Reader( )
。这尤其适用于大型数据集。举个例子:我正在读取 ~740000 行,执行查询需要 80-100 毫秒,读取所有数据大约需要 15 秒。另一个示例是读取 ~2200 行,查询时间为 ~200 毫秒和 ~1 秒以读取所有数据。
根据 High Performance MySQL检索到的数据缓冲在公共(public)连接器中(第 3 版,第 212 页),我认为这也适用于 Connector/Net。 .我知道在 740000 行的情况下,可能并非所有数据都可以或应该被缓冲,但应该可以轻松缓冲第二个示例中的 2200 行(我要求不超过 5-7 列)。
创建相当数量的数据结构而不从数据库中读取需要 <1 毫秒(使用 System.Diagnostics.Stopwatch 测量),因此这不是瓶颈。我想知道如果数据被缓冲,为什么从阅读器读取需要那么多时间。
最佳答案
要了解 MySqlDataReader
的工作原理,您需要了解 MySQL 协议(protocol)。假设未调用 MySqlCommand.Prepare()
,则 text protocol将被使用。
MySqlCommand.ExecuteReader
发送 COM_QUERY
数据包到服务器。 MySQL 服务器回复 text resultset .这包含一个标题,其中包含有关结果集中列的元数据,然后是所有行。
在实践中,我发现在查询“完成”之前服务器不会返回列元数据(例如,所有 WHERE
和 ORDER BY
条款已被评估);在复杂的查询中,这可能需要相当长的时间。返回列元数据后,MySqlCommand.ExecuteReader
返回一个 MySqlDataReader
对象。因此,“执行查询”是您测量的第一个延迟。
标准 while (reader.Read()) { }
循环然后继续读取从服务器流回的行数据包。此循环的速度取决于服务器发送数据包的速度以及客户端库反序列化数据包的速度。有些库比其他库快得多,例如,MySqlConnector 可以读取大量行 almost twice as fast作为连接器/NET(由于更高效的代码)。但您观察到的大部分时间只是接收然后阅读行。
在反序列化之前从网络堆栈中检索数据会产生一定的开销,这可能占总时间的很大一部分。新"Pipelines" feature .NET 的出现就是为了解决这个问题,因此我们将来可能会看到更快的 MySQL 连接库。
关于c# - 了解 MySqlDataReader 的内部结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26294714/