1 回答
TA贡献1802条经验 获得超4个赞
说明:
提供的解决方案的一部分是以下解释:
似乎在执行大量 SQL 语句时,Microsoft SQL Server 可能会在执行批处理中的所有语句之前停止处理该批处理。处理批处理的结果时,SQL Server 使用批处理创建的结果集填充连接的输出缓冲区。这些结果集必须由客户端应用程序处理。如果您正在执行具有多个结果集的大型批处理,SQL Server 会填充该输出缓冲区,直到它达到内部限制并且无法继续处理更多结果集。那时,控制权返回给客户端。此行为是设计使然。客户端应用程序应刷新所有待处理的结果集。一旦所有挂起的结果集都被客户端使用,SQL Server 就会完成批处理的执行。客户端应用程序可以调用 sqlsrv_next_result() 直到它返回 NULL。
因此,我认为 SQL 语句的长度没有限制,只有 PHP 字符串变量($InsertSQL
在您的情况下)的大小被限制为允许的最大 PHP 内存限制。这种意外行为的实际原因是,对于SET NOCOUNT OFF
(默认情况下)和大量的单个INSERT
语句,SQL Server 将受影响的行数作为结果集返回(例如(1 row affected)
)。
解决方案:
我能够重现此问题(使用 SQL Server 2012、PHP 7.1.12 和适用于 SQL Server 4.3.0+9904 的 PHP 驱动程序)并且您可以使用以下选项来解决此问题:
使用 刷新挂起的结果集
sqlsrv_next_result()
。在复杂的 T-SQL 语句中作为第一行执行
SET NOCOUNT ON
,以停止 SQL Server 将受影响的行数作为结果集返回。使用参数化语句使用
sqlsrv_prepare()\sqlsrv_execute()
桌子:
CREATE TABLE MyTable ( Column1 int, Column2 int, Column3 int)
一个复杂的语句(使用sqlsrv_query()
and sqlsrv_next_result()
):
<?php
// Connection info
$server = 'server\instance';
$database = 'database';
$username = 'username';
$password = 'password';
$cinfo = array(
"Database" => $database,
"UID" => $username,
"PWD" => $password
);
// Statement with sqlsrv_query
$sql = "";
for ($i = 1; $i <= 1000; $i++) {
$sql .= "INSERT INTO MyTable (Column1, Column2, Column3) VALUES (".$i.", 0, 0);";
}
$stmt = sqlsrv_query($con, $sql);
if ($stmt === false) {
echo "Error (sqlsrv_query): ".print_r(sqlsrv_errors(), true);
exit;
}
// Clean the buffer
while (sqlsrv_next_result($stmt) != null){};
// End
sqlsrv_free_stmt($stmt);
sqlsrv_close($con);
echo "OK";
?>
一个复杂的语句(使用sqlsrv_query()and SET NOCOUNT ON):
<?php
// Connection info
$server = 'server\instance';
$database = 'database';
$username = 'username';
$password = 'password';
$cinfo = array(
"Database" => $database,
"UID" => $username,
"PWD" => $password
);
// Connection
$con = sqlsrv_connect($server, $cinfo);
if ($con === false) {
echo "Error (sqlsrv_connect): ".print_r(sqlsrv_errors(), true);
exit;
}
// Statement with sqlsrv_query
$sql = "SET NOCOUNT ON;";
for ($i = 1; $i <= 1000; $i++) {
$sql .= "INSERT INTO MyTable (Column1, Column2, Column3) VALUES (".$i.", 0, 0);";
}
$stmt = sqlsrv_query($con, $sql);
if ($stmt === false) {
echo "Error (sqlsrv_query): ".print_r(sqlsrv_errors(), true);
exit;
}
// End
sqlsrv_free_stmt($stmt);
sqlsrv_close($con);
echo "OK";
?>
参数化语句(使用sqlsrv_prepare()and sqlsrv_execute()):
<?php
// Connection info
$server = 'server\instance';
$database = 'database';
$username = 'username';
$password = 'password';
$cinfo = array(
"Database" => $database,
"UID" => $username,
"PWD" => $password
);
// Connection
$con = sqlsrv_connect($server, $cinfo);
if ($con === false) {
echo "Error (sqlsrv_connect): ".print_r(sqlsrv_errors(), true);
exit;
}
$sql = "INSERT INTO MyTable (Column1, Column2, Column3) VALUES (?, ?, ?);";
$value1 = 0;
$value2 = 0;
$value3 = 0;
$params = array(&$value1, &$value2, &$value3);
$stmt = sqlsrv_prepare($con, $sql, $params);
if ($stmt === false ) {
echo "Error (sqlsrv_prepare): ".print_r(sqlsrv_errors(), true);
exit;
}
for ($i = 1; $i <= 1000; $i++) {
$value1 = $i;
$value2 = 0;
$value3 = 0;
$result = sqlsrv_execute($stmt);
if ($result === false) {
echo "Error (sqlsrv_execute): ".print_r(sqlsrv_errors(), true);
exit;
}
}
// End
sqlsrv_free_stmt($stmt);
sqlsrv_close($con);
echo "OK";
?>
- 1 回答
- 0 关注
- 155 浏览
添加回答
举报