读取您事先不知道其大小的整个LOB (没有最大分配+复制)应该是一个相当常见的问题,但是找到好的文档和/或示例来“正确”地做到这一点对我来说是非常令人抓狂的。
我尝试过使用SQLBindCol,但是看不出有什么好的方法可以让它工作。SQLDescribeCol和SQLColAttribute返回的列元数据似乎是列大小的默认值或上限,而不是当前LOB的实际大小。最后,我决定使用以下内容:
1)将any / all LOB列作为SELECT语句中编号最高的列
2) SQLPrepare语句
3) SQLBindCol任何您想要的早期非LOB列
4) SQLExecute语句
5) SQLFetch结果行
6)使用大小为0的缓冲区对LOB列执行SQLGetData操作,以便查询其实际大小
7)分配一个足以容纳LOB的缓冲区
8)这次使用正确大小的已分配缓冲区在LOB列上再次执行SQLGetData
9)对后面的每个LOB列重复步骤6-8
10)对结果集中的任何其他行重复步骤5-9
11)在处理完结果集后使用SQLCloseCursor
这似乎对我很有效,但似乎也相当复杂。
对SQLGetData的调用是返回到服务器还是只是处理已经发送到客户端的结果?
是否存在服务器和/或客户端将拒绝以这种方式处理非常大的对象的陷阱(例如,超过了某个大小阈值,因此它们会生成错误)?
最重要的是,有没有更好的方法呢?
谢谢!
发布于 2018-05-04 08:29:08
我看到了一些需要改进的地方。
MAX进行了改进:选择MAX(LENGTH(blob1)) AS max1,MAX(LENGTH(blob2)) AS max2,...
您可以使用max1和max2预先分配缓冲区,也可以只为所有列分配最大的缓冲区。
SQLGetData被设计为为每一列多次调用。只需再次调用它,使用相同的列号,它将获取下一个块。可用字节的计数将保存在StrLen_or_IndPtr (最后一个参数)所指向的位置。每次调用后,此计数都会随着获取的字节数而减少。当然,每次调用都会有到服务器的往返,因为这样做的目的是防止驱动程序获取超出应用程序处理能力的内容。
NULL作为缓冲区指针以获取长度的技巧是被禁止的在这种情况下,请检查微软文档上的SQLGetData。然而,你可以分配一个最小的缓冲区,比如8个字节,传递它和它的长度。该函数将返回写入的字节计数,在本例中为7,因为该函数添加了一个空字符,并将剩余字节的计数放入StrLen_or_IndPtr。但是如果你像上面解释的那样分配缓冲区,你可能不需要这样做。
注意:LOB必须位于选择列表的末尾,和必须按该顺序精确获取。
发布于 2018-04-26 17:14:28
SQLGetData
SQLGetData获取已获取结果的结果。例如,如果您对表的第一行执行了SQLFetch操作,SQLData会将您返回第一行。如果您不知道是否可以对结果执行SQLBindCol操作,则可以使用它。
但它的处理方式取决于您的驱动程序,并且在标准中没有描述。如果您的数据库是SQL数据库,则游标不能向后移动,因此结果可能仍在内存中。
大对象查询
根据服务器标准和您的ODBC Driver标准,服务器可能会拒绝处理大对象。在ODBC标准中没有对其进行描述。
发布于 2018-04-28 07:37:41
为了避免最大分配,执行额外的复制,并提高效率:
首先获得大小并不是一种坏方法--这实际上不需要额外的时间
SELECT LENGTH(your_blob) FROM ...然后进行分配并实际获取blob。
如果有多个BLOB列,则在一次遍历中获取所有长度:
SELECT LENGTH(blob1), LENGTH(blob2), ... FROM ...在MySQL中,BLOB或TEXT的长度位于字节前面。但是,即使它必须读取列才能获得长度,也可以将其视为只是启动缓存。也就是说,在这两种情况下,总体时间都不会受到太大影响。
https://stackoverflow.com/questions/50018049
复制相似问题