根据我的阅读,我发现使用MySQL JDBC驱动程序在MySQL中传输ResultSet
的方法是这两个命令:
stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_READ_ONLY);
stmt.setFetchSize(Integer.MIN_VALUE);
我的问题是专家可以澄清,如果使用上面的代码流式传输ResultSet会将一行返回给客户端,然后转到服务器以获取下一行等等(非常低效)或者它是否足够智能来执行缓冲流式处理BufferedStreamReader
?如果它是缓冲流,那么如何设置缓冲区大小?
编辑:来自doc:
只进,只读结果集与获取的组合 Integer.MIN_VALUE的大小用作驱动程序要流式传输的信号 结果逐行设置。在此之后,使用。创建的任何结果集 语句将逐行检索。
这是否意味着如果我有10M行,那么有10M往返服务器来获取这些行?这非常低效。我如何流式传输ResultSet
但是将其缓冲以便我不必进行这么多往返?
EDIT2:当fetchSize设置为Integer.MIN_VALUE时,似乎MySQL会自动执行一些缓冲。在我的测试中,我使用setFetchSize(Integer.MIN_VALUE)
在不到20分钟的时间内读取了超过40M的行。这相当于每秒约30,000行。我不知道平均行数有多大但很难想象每秒30,000次往返。
另外一个问题:如果结果集中的元素多于fetchSize,MySQL会怎么做?例如,结果集有10M行,fetchSize设置为1000.那么会发生什么?
答案 0 :(得分:3)
当fetchSize设置为Integer.MIN_VALUE时,似乎MySQL会自动执行一些缓冲。
至少有时候这样做。我使用Wireshark测试了MySQL Connector / J版本5.1.37的行为。对于表......
CREATE TABLE lorem (
id INT AUTO_INCREMENT PRIMARY KEY,
tag VARCHAR(7),
text1 VARCHAR(255),
text2 VARCHAR(255)
)
...带有测试数据......
id tag text1 text2
--- ------- --------------- ---------------
0 row_000 Lorem ipsum ... Lorem ipsum ...
1 row_001 Lorem ipsum ... Lorem ipsum ...
2 row_002 Lorem ipsum ... Lorem ipsum ...
...
999 row_999 Lorem ipsum ... Lorem ipsum ...
(where both `text1` and `text2` actually contain 255 characters in each row)
......和代码......
try (Statement s = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_READ_ONLY)) {
s.setFetchSize(Integer.MIN_VALUE);
String sql = "SELECT * FROM lorem ORDER BY id";
try (ResultSet rs = s.executeQuery(sql)) {
...紧接在s.executeQuery(sql)
之后 - 即,甚至在调用rs.next()
之前--MySQL Connector / J从表中检索了前140行。
实际上,只查询tag
列
String sql = "SELECT tag FROM lorem ORDER BY id";
MySQL Connector / J立即检索了所有1000行,如Wireshark网络框架列表所示:
将查询发送到服务器的第19帧看起来像这样:
MySQL服务器以第20帧响应,第20帧以...开头
......紧接着是第21帧,后面是......
...依此类推,直到服务器发送了第32帧,结束于
由于唯一的区别是每行返回的信息量,我们可以得出结论,MySQL Connector / J根据每个返回行的最大长度和可用的可用内存量决定适当的缓冲区大小。 / p>
如果结果集中的元素多于fetchSize,MySQL会怎么做?例如,结果集有10M行,fetchSize设置为1000.那么会发生什么?
MySQL Connector / J最初检索第一组fetchSize
行,然后当rs.next()
移动它们时,它最终将检索下一组行。即使对于setFetchSize(1)
也是如此,顺便说一下,真正一次只获得一行的方式。
(请注意,对于n> 0,setFetchSize(n)
在连接网址中需要useCursorFetch=true
。setFetchSize(Integer.MIN_VALUE)
显然不需要这样做。)