sqlsrv\u query是否限制了可以在一个查询中执行的语句数?

z2acfund  于 2021-07-26  发布在  Java
关注(0)|答案(1)|浏览(310)

我正在生成sql insert php中的语句 for 循环。
生成的sql字符串是大量单独的sql语句,如下所示:

INSERT INTO tbl VALUES(1,2,3);
INSERT INTO tbl VALUES(4,5,6);
INSERT INTO tbl VALUES(7,8,9);

等。。。
然后我执行:

$InsertResult = sqlsrv_query($conn, $InsertSQL);

问题是只执行前312条语句,而不是完整的2082行(表中只插入了312行)。
当我输出 $InsertSQL 变量,然后在ssms中手动执行它。它可以完美地工作并插入所有2082行。只有当我运行 $InsertSQL 可变通过 sqlsrv_query 它还没有完成。
我也没有得到任何错误,查询结果返回true,如此行中测试的:

if(!$InsertResult) die('Problem with Insert query: ' . $InsertSQL);

当我搜索这个问题的解决方案时,我看到了这一点(尽管php手册站点中没有提到) sqlsrv_query 很明显,在 $SQL 变量(约65k个字符)。
请参阅此处的另一篇stackoverflow文章:sqlsrv\u查询上sql变量的长度限制?
我认为这就是问题所在,所以创建了一个较短的字符串版本(只添加了我真正想要导入的列值)。然而,这个短得多的版本仍然只插入了前312行!所以现在看来这和最大字符串长度无关。事实上,如果是这样的话,我应该只得到大约250行(在250个语句之后,我大约有65k个字符)。
我也可以执行每个 insert 当然,这需要更长的时间。在我的测试中,这样做需要90秒左右,而在smss中手动运行组合语句只需要40秒左右。
请注意,我还研究了sql server的大容量插入,但是我无法将文件发送到安装了sql server的计算机(sql server和web服务器在不同的计算机上)。据我所知,这排除了这种可能性。
任何帮助都是非常感谢的,因为我甚至不知道是什么限制了我,更不用说修复它,我讨厌一次只能执行一行。

tkqqtvp1

tkqqtvp11#

说明:
发布在github上的这个驱动程序有一个关于执行大型sql语句的已知问题。提供的解决方案的一部分是以下说明:
似乎在执行一大批sql语句时,microsoft sql server可能会在执行该批中的所有语句之前停止处理该批。在处理批处理的结果时,SQLServer使用批处理创建的结果集填充连接的输出缓冲区。这些结果集必须由客户端应用程序处理。如果要执行包含多个结果集的大型批处理,SQLServer将填充该输出缓冲区,直到达到内部限制,并且无法继续处理更多的结果集。此时,控制权返回给客户机。这种行为是故意的。客户端应用程序应刷新所有挂起的结果集。一旦所有挂起的结果集被客户机使用,SQLServer就完成批处理的执行。客户端应用程序可以调用sqlsrv\u next\u 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() .
执行 SET NOCOUNT ON 作为复杂t-sql语句的第一行,停止sql server以将受影响行的计数作为结果集返回。
使用参数化语句 sqlsrv_prepare()\sqlsrv_execute() 表格:

CREATE TABLE MyTable (
    Column1 int,
    Column2 int,
    Column3 int
)

一个复杂语句(使用 sqlsrv_query() 以及 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() 以及 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() 以及 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";
?>

相关问题