【问题标题】:csv data import into mysql database using php使用php将csv数据导入mysql数据库
【发布时间】:2012-05-19 06:07:30
【问题描述】:

您好,我需要导入一个 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)' 附近使用正确的语法

我无法检测到这个错误...

文件每次只导入部分.. 在 10000 行中只导入大约 200 300 行..

【问题讨论】:

  • 如果您可以分享您的代码以及您正在处理的各种复杂情况,也许人们可以通过提出许多其他途径来做出更好的回应。
  • @somnath: 我已经添加了我的代码.. 我尝试了 set_time_limit(0) 但现在我遇到了一些 sql 语法错误..
  • set_time_limit() 与您遇到的错误无关。很可能您的代码没有进展到该代码并且由于提前达到 30 秒而过期!这是一个不同的错误,需要相应地解决。请在我的回答下方查看我的回复,了解我提出的一些建议。

标签: php mysql fgetcsv


【解决方案1】:

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

另一种解决方案是读取带有偏移量的文件:

  1. 阅读前 500 行,
  2. 将它们插入数据库
  3. 重定向到 csvimporter.php?offset=500
  4. 返回 1. 步骤,这次读取偏移量 500 开始的 500 行。

另一种解决方案是将超时限制设置为 0:

set_time_limit(0);

【讨论】:

  • 这将如何使整个工作更快更高效?
  • 如果您在谈论第一个解决方案,而不是逐行将值插入数据库,它将一次插入 500 行。你能说不影响执行吗?
  • 当然,如果他需要在不经过任何处理的情况下倾倒所有内容,情况会有所改善。但是,他提到他需要解析每一行。意味着他有逻辑在转储之前处理每一行。
  • 好的,但最后它会执行 INSERT 语句对吗?除非他需要优化线路处理的逻辑部分,否则这是我能想到的最佳答案。
  • 如果他要逐行插入,那么考虑到额外的 CPU 使用率来处理 1) 一次只加载 500 行而不是加载整个结果集然后 2,您的解决方案将花费更多时间) 转发到下一页调用以加载接下来的 500 行。除了内存极低的服务器无法读取内存中的 15000 行数据并需要使用硬盘缓存之外,所有服务器都会运行得更快。
【解决方案2】:

将此设置在页面顶部:

set_time_limit ( 0 )

它将使页面无休止地运行。但是,不建议这样做,但如果您别无选择,那就帮不上忙了!

您可以咨询documentation here

为了使其更快,您需要检查您发送的各种 SQL 并查看您是否创建了正确的索引。

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

【讨论】:

  • 这在一定程度上有效,但我遇到了一个我无法识别的 sql 语法错误。你能猜出错误在哪里吗?
  • @Neal 查看错误,我们可以看到 4 列中最后 3 列的数据。在我看来:purchase_value=0,purchase=0 和 company_id='S'。 company_id 是 char/varchar 字段吗?您能否提供表的数据结构以及删除 echo $sql 中的注释,以便您可以看到正在发送的 SQL 命令。提供与表结构一起显示的最后一条 SQL 命令。
  • 另外,尝试使用 TRUNCATE TABLE 命令,正如@tpaksu 提到的那样,这是从表中删除记录的最快方法,因为删除命令在截断表时保存在数据库日志文件中不是。 truncate table 命令删除的数据一旦发生数据库文件灾难,将永远无法恢复。
【解决方案3】:

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

更多信息请访问

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

【讨论】:

  • 他在逐行解析!他怎么能使用 LOAD DATA 呢?
  • 每一行的格式必须相同,即用 , 分隔的列不能相同,并且每列应该包含相同的数据类型。在这种情况下,您不需要解析每一行 mysql 实用程序 LOAD DATA INFILE 会为您执行此操作。
  • @Sachin Puri : 我可以在上面的 php 代码中使用这个 LOAD DATA 语句代替 sql INSERT 语句吗?
  • 是的,您可以这样做。使用以下查询: $q="LOAD DATA INFILE 'F:/www/temp.csv' into table temp FIELDS TERMINATED BY ','"; mysql_query($q);
  • 这个 F:/www/temp.csv 是指我的报告存储的路径吗?
【解决方案4】:

只需在你的 php 导入页面的开头使用这个@

ini_set('max_execution_time',0);

【讨论】:

  • 我已经尝试过了,但我又遇到了 sql 语法错误。它的内容是这样的。你的 SQL 语法有错误;检查与您的 MySQL 服务器版本相对应的手册,以在第 1 行的 'S',4511.16,4009.92)' 附近使用正确的语法
【解决方案5】:

问题:
将数据插入表的方式会对性能产生巨大影响。对于您的每一条记录,您向服务器发送一个 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 OR 10000 OR 15000,然后将数据插入到 vpireprot 表中,然后再次将 $q 设置为 INSERT INTO...
运行查询并享受!!!

【讨论】:

  • @علیرضا: 我正在尝试将 csv 数据插入到单个数据库表中...每次导入 csv 文件时,数据库表的所有先前内容都将被删除并新插入数据... 可以给我发一个示例教程吗?
  • 我现在不记得了,我是很久以前学的。
【解决方案6】:

如果这是一次性练习,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 实践以防止注入等。

【讨论】:

  • 他在逐行解析!他怎么能使用 LOAD DATA 呢?
  • 基本问题是将 CSV 数据加载到表中。如果他的 CSV 文件被正确字段以适合 LOAD DATA 方法,则不需要逐行解析。
  • @Eric Cope:我正在制作一个用于导入 csv 文件的前端页面。我正在使用 php 将数据从 csv 导入 mysql 。我应该如何在我的 php 中执行此语句文件?
  • 我编辑了我的答案。它只是一个 MySQL 查询,因此请像您在问题中提到的 INSERT 查询一样运行查询。
猜你喜欢
  • 1970-01-01
  • 2015-12-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-11
  • 1970-01-01
  • 2011-04-16
  • 1970-01-01
相关资源
最近更新 更多