草庐IT

PHP w/MS SQL 在批量插入时速度慢

coder 2024-04-20 原文

我在向 MSSQLSRV 2008 R2 中的暂存表中批量插入时遇到问题。

我正在插入约 200,000 行的 CSV,大约需要 5 分钟才能完成。

我尝试同时使用 PDO 和 sqlsrv 驱动程序。他们似乎都表现不佳。

这是让我了解我在做什么的代码(我包括了 SQLSRV 和 PDO 代码):

...
    try {
        //create structure table record
        foreach ($mapped_data as $k => $v) {
            $insert .= $k . ",";
            $values .= $v . ",";
        }
        $insert = substr($insert, 0, -1); //remove last ,
        $values = substr($values, 0, -1);
        $tableName = $table;
        if ($stageData) {
            $tableName = "stage_$table";
        }
        if ( $query == "" )
            $query = "INSERT INTO $tableName ($insert) VALUES ";
        $query .= "($values),";

        // Insert in blocks of 1000 lines
        if ($line % 1000 == 0) {
            $log->logInfo("Executing @ line: $line");
            $query = substr($query, 0, -1); //remove last ,
            $query .= ";";

            // ======================
            // = SQLSRV DRIVER CODE =
            // ======================
            sqlsrv_begin_transaction($sqlsrvConn);
            $queryResult = sqlsrv_query($sqlsrvConn,$query);
            if ($queryResult) {
                sqlsrv_commit($sqlsrvConn);
            } else {
                sqlsrv_rollback($sqlsrvConn);
            }

            // ===================
            // = PDO DRIVER CODE =
            // ===================
            $conn->beginTransaction();
            $res = $conn->prepare($query);
            if($res->execute() === false) {
                $errInfo = $res->errorInfo();
                if ( $conn->inTransaction() ) {
                    $conn->rollback();
                }
                $log->logInfo('Data importing error on line: ' . $line . $errInfo[2]);
                $errors[] = 'Data importing error on line: ' . $line . $errInfo[2];
            } else {
                if ( $conn->inTransaction() ) {
                    $conn->commit();
                    $query = "";
                    $importedRows += ($line - 6) - $importedRows;
                }
            }
        }
    }
    catch (PDOException $e) {
        if ( $conn->inTransaction() ) {
            $conn->rollBack();
        }
        $log->logInfo('PDO Exception: ' . $e->getMessage());
        $errors[] = 'PDO Exception: ' . $e->getMessage();
    }
    $line++;
} // End of while loop through each CSV Line

fclose($handle);
$totalRows = $line - 6;
$importedRows += $totalRows - $importedRows;

// Insert remaing queries afterwards...
...

我一直在互联网上搜索可能的解决方案,但未能找到任何有效的方法。

我找到了 this post这基本上是说将行一起批处理(我已经完成了)。

我发现另一篇帖子说 PDO 设置 connectionpooling=0。我试过了,但没有看到任何性能提升。

还有其他人在使用 SQLSRV 和 PHP 时遇到过这个问题吗?

干杯,

最佳答案

我有一个有点类似的问题。因为我的问题是可用内存不足,所以我的服务器不得不花费额外的时间来处理虚拟内存。如果那不是你的问题,我的回答对你没有用。

您正在使用字符串连接后跟 substr 来删除最后一个逗号。当你使用 substr 时,它会制作另一个字符串副本,这对于长字符串来说是内存密集型的。参见 this question例如,当字符串很长时会发生什么。当我切换到数组连接时,由于内存使用量较低,我的速度大大提高了。但是,如果您没有内存问题,数组连接实际上可能是 slower为你。

我看到的其他一些事情是您只需要收集 $inserts 变量一次,并且您不会在不再需要它们时立即取消设置大变量。我不知道纠正这种事情是否会对你产生明显的影响。以下是您可以尝试的基本更改类型:

    if(!isset($insert)) {
        $insert = array();
        $collect = true;
    }
    $values = $array();
    foreach ($mapped_data as $k => $v) {
        if(isset($collect)) 
            $insert[] = $k;
        $values[] = $v;
    }
    unset($collect);

    .....
    if(!isset($queryend)) 
         $queryend = array();
    $queryend[] = "(".implode(",",$values).")";

    .....
    $query = "INSERT INTO $tableName ("
             .implode(",",$insert)
             .") VALUES "
             .implode(",", $queryend);
    unset($queryend);  //always unset big things as soon as possible

    .....  //after $res = $conn->prepare($query);
    unset($query);

关于PHP w/MS SQL 在批量插入时速度慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19231473/

有关PHP w/MS SQL 在批量插入时速度慢的更多相关文章

  1. ruby - attr_accessor 在写入时将 nil 转换为字符串 - 2

    我有一个数据对象,其中包含许多用于各种输入的attr_accessor字段。我可以以某种方式定义类,以便所有字段的所有setter都将例如将值设置为空字符串而不是尝试的nil? 最佳答案 这里有一个小模块可以做到这一点:moduleNilToBlankAttrAccessordefnil_to_blank_attr_accessor(attr)attr_readerattrdefine_method"#{attr}="do|value|value=''ifvalue.nil?instance_variable_set"@#{attr

  2. ruby - 如何批量检查文件内容是否相同 - 2

    我想使用Ruby检查数千对文件中的每对文件是否包含相同的信息。有人能指出我正确的方向吗? 最佳答案 require'fileutils'FileUtils.compare_file('file1','file2')当且仅当文件file1和file2相同时返回true。 关于ruby-如何批量检查文件内容是否相同,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/33769865/

  3. java - Ruby 和 Java 的速度 - 2

    按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭10年前。在我在网上找到的每个基准测试中,Ruby似乎都很慢,比Java慢得多。Ruby的人只是说这无关紧要。您能举个例子说明RubyonRails(以及Ruby本身)的速度真的无关紧要吗?

  4. ruby-on-rails - 在 Rails 中使用 accepts_nested_attributes_for + 批量赋值保护 - 2

    假设你有这个结构:classHouse请注意,Tv的用户是故意不可访问的。所以你有一个三层嵌套的表单,允许你在一个页面上输入房子、房间和电视。这是Controller的创建方法:defcreate@house=House.new(params[:house])if@house.save#...standardstuffelse#...standardstuffendend问题:您究竟如何为每台电视填充user_id(它应该来自current_user.id)?什么是好的做法?这是我在其中看到的catch22。将user_ids直接填充到params散列中(它们嵌套得很深)保存将失败,因

  5. ruby-on-rails - Ruby 的 range step 方法导致执行速度很慢? - 2

    我有这段代码:date_counter=Time.mktime(2011,01,01,00,00,00,"+05:00")@weeks=Array.new(date_counter..Time.now).step(1.week)do|week|logger.debug"WEEK:"+week.inspect@weeks从技术上讲,代码有效,输出:SatJan0100:00:00-05002011SatJan0800:00:00-05002011SatJan1500:00:00-05002011etc.但是执行时间完全是垃圾!每周计算大约需要四秒钟。我在这段代码中是否遗漏了一些奇怪的低效

  6. ruby - 如何使用 bash 命令或 Ruby 使用 ffmpeg 将 mp4 文件批量转换为 ogg - 2

    我运行的是OSX,对视频转换一无所知。但我有大约200个视频都是mp4格式,无法在Firefox中播放。我需要将它们转换为ogg才能使用html5视频标签。这些文件位于一个文件夹结构中,这使得一次一个地处理一个文件变得困难。我希望bash命令或Ruby命令遍历所有子文件夹并找到所有.mp4并转换它们。我找到了一份关于如何使用Google执行此操作的引用资料:http://athmasagar.wordpress.com/2011/05/12/a-bash-script-to-convert-mp4-files-to-oggogv/#!/bin/bashforfin$(ls*mp4|se

  7. ruby-on-rails - XPath 或 CSS 解析速度更快(对于 HTML 文件上的 Nokogiri)? - 2

    我想知道NokogiriXPath或CSS解析是否可以更快地处理HTML文件。速度有何不同? 最佳答案 Nokogiri没有XPath或CSS解析。它将XML/HTML解析为单个DOM,然后您可以使用CSS或XPath语法进行查询。CSS选择器在要求libxml2执行查询之前在内部转换为XPath。因此(对于完全相同的选择器)XPath版本会快一点点,因为CSS不需要先转换成XPath。但是,您的问题没有通用答案;这取决于您选择的是什么,以及您的XPath是什么样的。很有可能,您不会编写与Nokogiri创建的相同的XPath。例如

  8. ruby-on-rails - 仅当该表尚未加入时才可以加入 "dynamically"表吗? - 2

    我正在使用RubyonRails3.2.2,我想知道在范围方法中是否可以“动态”连接一个表,前提是该表尚未连接。那它,我有:defself.scope_method_name(user)joins(:joining_association_name).where("joining_table_name.user_id=?",user.id)end我想做如下的东西:#Note:thefollowingcodeisjustasampleinordertounderstandwhatImean.defself.scope_method_name(user)iftable_is_joined?

  9. ruby - 阅读用户输入时如何避免回显换行符? - 2

    我正在用Ruby编写类似curses的程序,我正在使用stty和ansi转义字符来实现我想要的。当我想获得用户输入时,我的问题就出现了。像许多基于控制台的程序一样,我想从终端底部获取用户输入。因此,我将光标放在屏幕底部并调用Readline.readline(或任何获取用户输入的方法)。像往常一样,它会读取所有内容,直到我按下回车键,并打印一个换行符。由于光标位于终端的最后一行,它会滚动一行,这会弄乱屏幕。我怎样才能避免这种情况?我试图使用stty来停止回显换行符,但我没有成功。也许可以使用stty来阻止终端滚动?当然,我可以编写自己的方法来通过一次读取一个字符(并捕获“返回”)来捕获

  10. ruby - Ruby 线程不能在写入时发生冲突吗? - 2

    在过去的C#和Java工作中,我习惯于这样的声明不是线程安全的:x+=y;但是,在与Ruby并行运行上述代码时,我未能观察到任何线程间的冲突。我读过Rubyautomaticallypreventsmultiplethreadsfromwritingtothesamedataconcurrently.这是真的?因此+=运算符在Ruby中是线程安全的吗? 最佳答案 好吧,这取决于您的实现和很多事情。在MRI中,有一个GVL(GiantVMLock)这样的东西,它控制哪个线程一次实际执行代码。你看,在MRI中,一次只有一个线程可以执行R

随机推荐