【问题标题】:Understanding internals of MySqlDataReader了解 MySqlDataReader 的内部结构
【发布时间】:2014-10-10 08:09:50
【问题描述】:

我想了解 MySqlDataReader(或一般的 IDataReader)的怪癖。在互联网上进行研究时,我发现了很多关于如何使用 MySqlDataReader 的资源,但对幕后发生的事情却知之甚少。我之所以问,是因为我发现在某些基准测试中,我执行执行MySqlCommand.ExecuteReader() 所需的时间比使用MySqlDataReader.Reader() 读取我的所有数据集要小几个数量级。这尤其适用于大型数据集。举个例子:我正在读取 ~740000 行,执行查询需要 80-100 毫秒,读取所有数据大约需要 15 秒。另一个例子是读取约 2200 行,查询时间约 200 毫秒,读取所有数据约 1 秒。

根据High Performance MySQL,检索到的数据缓冲在通用连接器中(第 3 版,第 212 页),我假设这也适用于Connector/Net。我知道在 740000 行的情况下,可能并非所有数据都可以或应该被缓冲,但在第二个示例中应该可以轻松缓冲 2200 行(我要求不超过 5-7 列)。

在不从数据库读取的情况下创建相当数量的数据结构需要

【问题讨论】:

  • “创建可比较数量的数据结构” 不清楚您测量了什么,ToList())。虽然DataReader 分批流式传输行,但它仍然需要执行查询才能开始处理行。如果查询很昂贵,则阅读器必须等到第一行被流式传输。也许您需要添加缺失的索引或以其他方式优化您的查询。

标签: c# mysql mysqldatareader


【解决方案1】:

要了解MySqlDataReader 的工作原理,您需要了解 MySQL 协议。假设没有调用MySqlCommand.Prepare(),那么将使用text protocol

MySqlCommand.ExecuteReader 向服务器发送一个COM_QUERY 数据包。 MySQL 服务器回复text resultset。这包含一个标题,其中包含有关结果集中列的元数据,然后是所有行。

在实践中,我发现在查询“完成”之前,服务器不会返回列元数据(例如,所有 WHEREORDER BY 子句都已评估);在复杂的查询中,这可能需要相当长的时间。返回列元数据后,MySqlCommand.ExecuteReader 返回一个 MySqlDataReader 对象。所以“执行查询”是你衡量的第一个延迟。

标准的while (reader.Read()) { } 循环然后继续读取从服务器流回的行数据包。这个循环的速度取决于服务器发送数据包的速度以及客户端库反序列化它们的速度。一些库比其他库快得多,例如,MySqlConnector 可以读取大量行 almost twice as fast 作为连接器/NET(由于更高效的代码)。但是您观察到的大部分时间只是接收然后读取行。

在反序列化之前从网络堆栈中检索数据会产生一定的开销,这可能占总时间的很大一部分。 .NET 新的"Pipelines" feature 就是为了解决这个问题,所以我们将来可能会看到更快的 MySQL 连接库。

【讨论】:

    猜你喜欢
    • 2019-01-08
    • 2010-09-21
    • 2019-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-10
    • 1970-01-01
    相关资源
    最近更新 更多