Redshift ODBC 2.x适配pyodbc超4KB大字段读取问题咨询
Redshift ODBC 2.x 适配pyodbc读取超4KB数据的问题修复方案
问题重现代码
import pyodbc query = 'SELECT REPEAT(\'a\', 5000)' # 修正原代码中statement变量未定义的问题 cnxn = pyodbc.connect('Driver={Amazon Redshift ODBC Driver (x64)}; Server=srv.amazonaws.com...') cursor = cnxn.cursor() cursor.execute(query) val = cursor.fetchall()[0][0]
问题现象
执行上述代码后,val的值在2046字符后出现损坏,无法完整获取5000字符的完整数据。
问题分析
查看pyodbc与ODBC规范及源码后发现:
- pyodbc默认初始分配4KB缓冲区调用
SQLGetData,Redshift ODBC驱动填充4KB数据后返回实际数据总大小(如5000字节)。 - pyodbc随后重新分配对应大小的缓冲区,设置已使用字节数
cbUsed为4KB,再次调用SQLGetData,期望驱动从上次的偏移位置续写剩余数据。 - 但Redshift ODBC 2.x驱动未实现状态维护逻辑,无法记录已读取的位置,每次调用
SQLGetData都会从头写入数据,导致后续数据覆盖或损坏。
核心问题解答
1. ODBC是否需要保持状态?
根据ODBC官方规范,支持分段读取大字段的驱动必须维护状态。当应用程序多次调用SQLGetData读取同一字段时,驱动需要记录当前已读取的偏移量,后续调用时从该位置继续返回剩余数据。Redshift ODBC 2.x的行为不符合这一规范,属于驱动实现缺陷。
2. 如何确定需写入的数据块?
对于符合规范的ODBC驱动:
- 首次调用
SQLGetData时,驱动返回字段总长度,同时将缓冲区填满至最大容量(如4KB)。 - 后续调用时,驱动根据已维护的读取状态,计算剩余未读取的数据长度,将剩余数据写入新缓冲区的对应偏移位置,直到数据全部读取完成。
- 若驱动不支持状态维护,只能通过调整应用层逻辑或驱动配置来规避问题。
可行修复方案
- 方案一:升级Redshift ODBC驱动
Amazon后续发布的Redshift ODBC 3.x版本已修复该分段读取的状态维护问题,升级至最新版驱动是最彻底的解决方案。 - 方案二:增大pyodbc初始缓冲区
修改pyodbc的默认初始缓冲区大小,使其超过你的最大字段长度(比如设置为10KB)。可以通过连接字符串参数MaxLongVarcharSize(部分驱动支持)调整,或修改pyodbc源码中默认缓冲区配置后重新编译。 - 方案三:应用层手动拆分读取
若无法升级驱动,可在SQL查询中手动将大字段拆分为多个小片段读取,再在Python中拼接:
然后在代码中执行SELECT SUBSTRING(long_column, 1, 4000) AS part1, SUBSTRING(long_column, 4001, 5000) AS part2 FROM your_table;full_data = part1 + part2得到完整内容。
内容的提问来源于stack exchange,提问作者rahman
相关产品推荐
相关产品推荐

