读取一个事先不知道其大小的整个lob(没有max allocation+copy)应该是一个相当常见的问题,但是找到一个好的文档和/或例子来用“正确”的方法来实现这一点对我来说是非常恼火的。
我和他摔跤 SQLBindCol
但却找不到什么好办法。 SQLDescribeCol
以及 SQLColAttribute
返回列元数据,该元数据似乎是列大小的默认值或上限,而不是当前lob的实际大小。最后,我决定使用以下方法:
1) 将任何/所有lob列作为select语句中编号最高的列
2) SQLPrepare
声明
3) SQLBindCol
需要的任何早期非lob列
4) SQLExecute
声明
5) SQLFetch
结果行
6) SQLGetData
在lob列上使用大小为0的缓冲区来查询其实际大小
7) 分配一个足以容纳lob的缓冲区
8) SQLGetData
再次在lob列上使用大小正确的分配缓冲区
9) 对后面的每个lob列重复步骤6-8
10) 对结果集中的其他行重复步骤5-9
11) SQLCloseCursor
当你完成你的结果集
这似乎对我有效,但也似乎相当复杂。
对sqlgetdata的调用是返回到服务器还是仅仅处理已经发送到客户端的结果?
服务器和/或客户机是否会拒绝以这种方式处理非常大的对象(例如,超过某个大小阈值,因此它们会生成错误)?
最重要的是,有没有更好的办法?
谢谢!
3条答案
按热度按时间eeq64g8w1#
要避免最大分配,执行额外的复制,并提高效率,请执行以下操作:
首先得到尺寸并不是一个坏方法——它几乎不需要额外的时间
然后执行分配并实际获取blob。
如果有多个blob列,则在一次传递中获取所有长度:
在mysql中,一个
BLOB
或者TEXT
在字节前面随时可用。但是,即使它必须读取列才能获得长度,也可以认为这只是启动缓存。也就是说,无论哪种情况,总的时间都不会受到太大的影响。gg0vcinb2#
sqlgetdata数据库
SQLGetData
获取已获取结果的结果。例如,如果你有SQLFetch
你table的第一排,SQLData
我会把你送回第一排。如果你不知道你能不能用它SQLBindCol
结果。但它是如何处理取决于您的司机,而不是描述在标准。如果您的数据库是sql数据库,则游标不能向后移动,因此结果可能仍在内存中。
大对象查询
根据服务器标准和odbc驱动程序标准,服务器可能拒绝处理大型对象。odbc标准中没有对其进行描述。
bkkx9g8r3#
我看到有几个改进要做。
如果需要分配缓冲区,那么应该为所有记录和列分配一次缓冲区。所以,你可以使用@rickjames建议的技巧,通过
MAX
这样地:选择max(length(blob1))作为max1,max(length(blob2))作为max2。。。
你可以用
max1
以及max2
预先分配缓冲区,或者只为所有列分配最大的缓冲区。返回的缓冲区长度为1。对于您的应用程序来说可能太大。您可以在运行时决定缓冲区的大小。不管怎样,
SQLGetData
被设计为对每个列多次调用。只需使用相同的列号再次调用它,它将获取下一个块。可用字节数将保存在StrLen_or_IndPtr
(最后一个论点)要点。每次调用后,此计数将随着获取的字节数而减少。当然,每次调用都会有到服务器的往返,因为这样做的目的是防止驱动程序获取超出应用程序处理能力的数据。
传球的诀窍
NULL
由于在这种情况下禁止使用缓冲区指针来获取长度,请检查microsoft文档上的sqlgetdata。但是,您可以分配一个最小的缓冲区,比如说8个字节,传递它和它的长度。函数将返回写入的字节数,在本例中为7,因为函数添加了一个空字符,并将
StrLen_or_IndPtr
剩余字节的计数。但是,如果按照上面的说明分配缓冲区,则可能不需要这个。注意:lob必须位于select列表的末尾,并且必须按照该顺序精确地获取。