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

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 服务器位于不同的计算机上)。据我了解,这消除了这种可能性。


非常感谢任何帮助,因为我什至无法弄清楚是什么限制了我,更不用说修复它了,我不想一次只执行一行。


慕村9548890
浏览 156回答 1
1回答

慕虎7371278

说明:提供的解决方案的一部分是以下解释:似乎在执行大量 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 bufferwhile (sqlsrv_next_result($stmt) != null){};// Endsqlsrv_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;}// Endsqlsrv_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;    }}// Endsqlsrv_free_stmt($stmt);sqlsrv_close($con);echo "OK";?>
打开App,查看更多内容
随时随地看视频慕课网APP