使用php将csv数据导入mysql数据库

时间:2012-05-19 06:07:30

标签: php mysql fgetcsv

您好我需要导入15000行的csv文件。 我使用fgetcsv函数并解析每一行.. 但我每次都会收到超时错误。 该过程太慢,数据部分导入。 有没有办法让数据导入更快更有效?

if(isset($_POST['submit']))
{

 $fname = $_FILES['sel_file']['name'];
 $var = 'Invalid File';
 $chk_ext = explode(".",$fname);

 if(strtolower($chk_ext[1]) == "csv")
 {

     $filename = $_FILES['sel_file']['tmp_name'];
     $handle = fopen($filename, "r");
 $res = mysql_query("SELECT * FROM vpireport");
 $rows = mysql_num_rows($res);
 if($rows>=0)
{
    mysql_query("DELETE FROM vpireport") or die(mysql_error());

    for($i =1;($data = fgetcsv($handle, 10000, ",")) !== FALSE; $i++)
    {
        if($i==1)
        continue;
        $sql = "INSERT into vpireport
                                (item_code,
                                 company_id,
                                 purchase,
                                 purchase_value) 
                                 values
                                (".$data[0].",
                                 ".$data[1].",
                                 ".$data[2].",
                                 ".$data[3].")";
        //echo "$sql";
        mysql_query($sql) or die(mysql_error());
    }
}

 fclose($handle);
?>
 <script language="javascript">
 alert("Successfully Imported!");
 </script>
 <?

} 问题是每次它陷入导入过程之间并显示以下错误:

错误1: 致命错误:第175行超过30秒的最长时限。

错误2:

您的SQL语法有错误;检查与MySQL服务器版本对应的手册,以便在第1行“S”,0,0)附近使用正确的语法

此错误我无法检测到......

该文件每次都是部分导入的..大约200 300行中的200 300行。

6 个答案:

答案 0 :(得分:3)

将此设置在页面顶部:

set_time_limit ( 0 )

它将使页面无休止地运行。但是,不推荐这样做,但如果您没有其他选择,则无法提供帮助!

您可以参考documentation here

为了加快速度,您需要检查要发送的各种SQL,看看是否创建了正确的索引。

如果您正在调用用户定义的函数并且这些函数引用全局变量,那么您可以通过将这些变量传递给函数并更改代码以使函数引用那些传递的变量来最小化所需的时间。引用全局变量比局部变量慢。

答案 1 :(得分:3)

您可以为每500行csv构建一个批量更新字符串,然后如果您在每行上执行mysql插入,则立即执行它。它会更快。

另一种解决方案是使用偏移量读取文件:

  1. 阅读前500行,
  2. 将它们插入数据库
  3. 重定向到csvimporter.php?offset = 500
  4. 返回1.步骤并读取此次以偏移500开始的500行。
  5. 另一种解决方案是使用以下方法将超时限制设置为0

    set_time_limit(0);
    

答案 2 :(得分:2)

你可以使用LOAD DATA INFILE这是一个mysql实用程序,这比fgetcsv快得多

提供更多信息

http://dev.mysql.com/doc/refman/5.1/en/load-data.html

答案 3 :(得分:1)

只需使用此@在php导入页面的开头

ini_set('max_execution_time',0);

答案 4 :(得分:1)

如果这是一次性练习,PHPMyAdmin支持通过CSV导入。 import-a-csv-file-to-mysql-via-phpmyadmin

他还注意到用户利用MySQL的LOAD DATA LOCAL INFILE。这是将数据导入数据库表的一种非常快速的方法。 load-data Mysql Docs link

编辑:

这是一些伪代码:

// perform the file upload 
$absolute_file_location = upload_file();

// connect to your MySQL database as you would normally
your_mysql_connection();

// execute the query
$query = "LOAD DATA LOCAL INFILE '" . $absolute_file_location . 
         "' INTO TABLE `table_name`
         FIELDS TERMINATED BY ','
         LINES TERMINATED BY '\n'
         (column1, column2, column3, etc)";
$result = mysql_query($query);

显然,您需要确保良好的SQL实践以防止注入等。

答案 5 :(得分:1)

<强>问题:
将数据插入表中的方式会对性能产生巨大影响。对于你的每一条记录,你都向服务器发送一个INSERT请求,15000个INSERT请求是巨大的!

<强>解:
那么你应该像mysqldump那样对你的数据进行分组。在您的情况下,您只需要三个插入语句而不是15000,如下所示:

在循环写入之前

$q = "INSERT into vpireport(item_code,company_id,purchase,purchase_value)values";

在循环内部将记录连接到查询,如下所示:

$q .= "($data[0],$data[1],$data[2],$data[3]),";

在循环内检查计数器是否等于5000或10000或15000然后将数据插入vpireprot表,然后再将$ q设置为INSERT INTO...。 运行查询并享受!!!