增强csv文件数据库导入

时间:2014-11-05 14:34:23

标签: php mysql csv pdo

我使用下面的脚本将大型csv文件导入我的数据库。

如果表格为空,则在本地计算机上完成该过程大约需要5分钟。

如果我使用该文件更新同一个表上的现有值,则需要15分钟才能完成。

我的csv文件包含大约35,000行。

如何加快这个过程?

    if ( $request->get( $_POST["action"] ) == "import" ) {

        $file = $upload->file_upload( "import", "media/import" );
        if ( file_exists( DIR_UPLOAD_PHOTO . "/media/import/" . $file ) ) {

            $file   = DIR_UPLOAD_PHOTO . "/media/import/" . $file;
            $handle = fopen( $file, "r" );

            if ( $handle ) {
                $lines = explode( "\r", fread( $handle, filesize( $file ) ) );
            }

            $total_array = count( $array );

            $x = 0;

            foreach ( $lines as $line ) {

                if ( $x >= 1 ) {
                    $data = explode( "|", $line );

                    $titlu          = trim( addslashes( $data[0] ) );
                    $alias          = $this->generate_seo_link( $titlu );
                    $gramaj         = trim( $data[1] );
                    $greutate       = trim( $data[2] );
                    $pret_total     = trim( $data[3] );
                    $pret_redus     = trim( $data[4] );
                    $poza           = trim( $data[5] );
                    $pret_unitar    = trim( $data[6] );
                    $categorie      = trim( $data[7] );
                    $brand          = trim( addslashes( $data[8] ) );
                    $descriere      = trim( addslashes( $data[9] ) );
                    $vizibil        = trim( $data[10] );
                    $cod            = trim( $data[11] );
                    $nou            = trim( $data[12] );
                    $cant_variabila = trim( $data[13] );
                    $congelat       = trim( $data[14] );
                    $tva            = trim( $data[15] );
                    $stoc           = trim( $data[16] );

                    if ( $cod != "" && $cod != " " ) {

                        $verificare = $database->select( "SELECT alias FROM produse WHERE alias LIKE '%" . $alias . "%'" );
                        for ( $i = 0; $i < $database->countRows(); $i++ ) {
                            if ( $alias == $verificare['alias'][$i] ) {
                                $alias = $this->increment_string( $alias, '_', 1 );
                            } else {
                                $alias = $alias;
                            }
                        }

                        $database->insert( sprintf( "insert into produse set
                            titlu='%s',
                            alias='%s',
                            gramaj='%s',
                            greutate='%s',
                            prettotal='%s',
                            pretredus='%s',
                            poza='%s',
                            pretunitar='%s',
                            categorie='%d',
                            brand='%s',
                            descriere='%s',
                            vizibil='%d',
                            cod='%s',
                            nou='%d',
                            cant_variabila='%d',
                            congelat = '%d',
                            tva = '%s',
                            stoc = '%d'

                            on duplicate key update

                            titlu='%s',
                            gramaj='%s',
                            greutate='%s',
                            prettotal='%s',
                            pretredus='%s',
                            poza='%s',
                            pretunitar='%s',
                            categorie='%d',
                            brand='%s',
                            descriere='%s',
                            vizibil='%d',
                            cod='%s',
                            nou='%d',
                            cant_variabila='%d',
                            congelat = '%d',
                            tva='%s',
                            stoc= '%d'",

                            $titlu, $alias,
                            $gramaj, $greutate, $pret_total, $pret_redus, $poza, $pret_unitar, $categorie,
                            $brand, $descriere, $vizibil, $cod, $nou, $cant_variabila, $congelat,
                            $tva, $stoc,

                            $titlu, $gramaj, $greutate,
                            $pret_total, $pret_redus, $poza, $pret_unitar, $categorie, $brand, $descriere,
                            $vizibil, $cod, $nou, $cant_variabila, $congelat, $tva, $stoc ) );

  }
  }
  $x++;
    }

   }
  }

这是我的递增功能

  function increment_string($str, $separator = '-', $first = 1){
    preg_match('/(.+)'.$separator.'([0-9]+)$/', $str, $match);

    return isset($match[2]) ? $match[1].$separator.($match[2] + 1) : $str.$separator.$first;

  }

2 个答案:

答案 0 :(得分:1)

首先,你做的越少 - 它就越快。但是,由于硬盘驱动器,许多数据库导入都很慢。不是因为CPU,不是因为RAM不足 - 这是硬盘驱动器。

原因如下:硬盘按每秒输入输出操作运行 - 我将其称为I / O.这是制造商不做广告的数量。他们宣传像带宽和爆裂读取这样的东西,这些都是无用的数字 - 就像老鼠的DPI一样。

机械磁盘的I / O数量相对较少。该数量取决于驱动器,它可以是100到400 I / O之间的任何值。 SSD具有更多可用的I / O,从5000到80k(甚至更多)。

这意味着机械磁盘可以在1秒内执行400次写入,而SSD可以执行5000次写入。 问题在于数据库查询通常很小(大约4KB)。

如果你做简单的数学运算 - 400 I / O * 4KB - 你会得到~1.6 MB /秒的数字。它表明你花费了所有的I / O,但坚持了磁盘带宽的所有容量。

这也暗示您可以为每个I / O发出更大的数据写入。 在凡人语言中,它只是意味着你应该启动一个事务,发出几个INSERT查询(比如说,50个INSERT),然后提交事务。

这样你就花费了1个I / O来插入50个插件。反过来,它的速度提高了50倍。如果您要使用预准备语句,这将变得更加高效,因为MySQL不必在每次发送时都使用查询。

我不会发送任何代码,因为您应该能够自行修复它。此外,您的代码对SQL注入是开放的。你需要修改一些东西,如果你不确定准备好的陈述是什么 - 请大声回答。

答案 1 :(得分:0)

将SELECT推入INSERT,以便它们全部在服务器上运行,而不是从客户端返回到服务器的第四位。