为了账号安全,请及时绑定邮箱和手机立即绑定

sqlsrv_query 是否限制一个查询中可以执行的语句数?

sqlsrv_query 是否限制一个查询中可以执行的语句数?

PHP
慕村9548890 2023-04-28 15:16:00
insert我在 PHP循环中生成 SQL语句for。生成的 SQL 字符串是大量单独的 SQL 语句,如下所示:INSERT INTO tbl VALUES(1,2,3);INSERT INTO tbl VALUES(4,5,6);INSERT INTO tbl VALUES(7,8,9);ETC...然后我执行:$InsertResult = sqlsrv_query($conn, $InsertSQL);问题是只有前 312 条语句被执行,而不是完整的 2082 行(只有 312 行被插入到表中)。当我将$InsertSQL变量输出到 JavaScript 控制台,然后在 SSMS 中手动执行它时,它完美地工作并插入了所有 2082 行。只有当我运行$InsertSQL变量时sqlsrv_query它才不会完成。我也没有收到任何错误,并且查询结果返回 true,如下行所示:if(!$InsertResult) die('Problem with Insert query: ' . $InsertSQL);当我搜索此问题的解决方案时,我看到(尽管 PHP 手册站点中未提及)sqlsrv_query显然对变量有字符串字符限制$SQL(大约 65k 个字符)。请在此处查看另一篇 StackOverflow 文章: sqlsrv_query 上的 sql 变量的长度限制?我认为这是问题所在,因此创建了一个较短版本的字符串(通过仅添加我实际想要导入的列值)。然而,这个短得多的版本仍然只插入前 312 行!所以现在看来这与最大字符串长度无关。事实上,如果是的话,我应该只得到大约 250 行(在 250 条语句之后我大约有 65k 个字符)。我也可以insert单独执行每个语句,但这当然需要更长的时间。在我的测试中,这样做需要 90 秒左右,而在 SMSS 中手动运行组合语句只需要大约 40 秒。请注意,我还查看了 SQL Server 的批量插入,但是我无法将文件发送到安装了 SQL Server 的机器(SQL Server 和 Web 服务器位于不同的计算机上)。据我了解,这消除了这种可能性。非常感谢任何帮助,因为我什至无法弄清楚是什么限制了我,更不用说修复它了,我不想一次只执行一行。
查看完整描述

1 回答

?
慕虎7371278

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";

?>



查看完整回答
反对 回复 2023-04-28
  • 1 回答
  • 0 关注
  • 155 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信