PHP使用sqlsrv_query查询SQL Server仅返回部分数据该如何解决
结论
该问题和数据量过大无关,4000行结构化数据的体量极小,完全可以正常获取全部查询结果,数据丢失是代码逻辑错误搭配SQLSRV扩展默认配置限制共同导致的。
根因分析
- 代码逻辑bug:内层遍历行的while循环中,
$j变量仅在进入每个结果集时初始化为0,遍历过程中没有做自增操作,每次读取新行都会覆盖$result[$i][0]的位置,正常逻辑下甚至只能拿到每个结果集的最后一行。你当前能拿到3000行是因为触发了第二个配置问题。 - SQLSRV扩展默认缓冲区限制:sqlsrv扩展默认开启客户端结果缓存,单查询默认最多缓存2.5MB的结果数据,按你表的字段结构计算,单条行数据约850字节,2.5MB刚好只能缓存3000行左右,超出部分不会被加载到缓冲区,导致读取中断。
修复方案
1. 修复计数逻辑+调大缓冲区
你当前的代码外层do-while是用来处理多结果集的场景,如果你的业务确实存在多结果集返回的情况,可以用以下修复后的代码:
$sql = 'SELECT * FROM ExampleData'; // 调大客户端缓冲区到10MB,足够容纳全部4000行数据 $options = [ 'Scrollable' => SQLSRV_CURSOR_CLIENT_BUFFERED, 'ClientBufferMaxKBSize' => 10240 ]; $query = sqlsrv_query($conn, $sql, [], $options); if ($query === false) return null; $result = []; do { $currentSet = []; while ($row = sqlsrv_fetch_array($query, SQLSRV_FETCH_ASSOC)) { // 直接用数组追加,不需要手动维护i、j计数,避免遗漏自增的问题 $currentSet[] = $row; } if (!empty($currentSet)) { $result[] = $currentSet; } } while (sqlsrv_next_result($query)); return $result;
2. 简化单结果集查询逻辑
你当前的SQL只有单条SELECT语句,不存在多结果集的情况,完全可以去掉外层do-while循环,代码简化后更不容易出问题:
$sql = 'SELECT * FROM ExampleData'; $options = ['ClientBufferMaxKBSize' => 10240]; $query = sqlsrv_query($conn, $sql, [], $options); if ($query === false) return null; $result = []; while ($row = sqlsrv_fetch_array($query, SQLSRV_FETCH_ASSOC)) { $result[] = $row; } return $result;
验证方案
修改后可以先调用sqlsrv_num_rows($query)打印返回的总行数,确认SQL Server侧已经返回了全部4000行数据,再排查后续逻辑问题。
内容的提问来源于stack exchange,提问作者haon
相关产品推荐
相关产品推荐

