【问题标题】:mysql | DB table import strategymysql | DB表导入策略
【发布时间】:2014-03-28 13:46:39
【问题描述】:

我正在编写数据库导入函数。我的语言是php。我的数据是 JSON 格式。

我的代码如下:

public function import($data = '') {

    if (!isset($data)) {
        return array(
            'error' => "Error: no data"
        );  
    }

    $data_arr = json_decode($data, true);

    if (is_array($data_arr) && sizeof($data_arr)) {

        // Truncate DB table

        $sql = 'TRUNCATE `ms_data`';
        $this->db->query($sql)->execute();

        // Import data
        $sql =  'INSERT INTO `ms_data` (
                `id`, 
                `name`, 
                `parent`, 
                `ordering`
                ) VALUES (
                    :id,
                    :name, 
                    :parent,  
                    :ordering
                )';

        foreach($data_arr as $d) {

            $this->db->query($sql)
                ->bind(":id",        $d['id'])
                ->bind(":name",      trim($d['name']))
                ->bind(":ordering", $d['ordering'])
                ->execute();
        }

        return array(
            'status' => 1,
            'message' => 'Data has been imported'
        );                  

    } else {

        return array(
            'error' => "Input is not array"
        );  
    }       
}

这是工作代码,但是:也许您知道上面我现在不知道的任何代码问题或任何改进建议?

谢谢!

【问题讨论】:

  • 希望您永远不必处理大量数据
  • 这个功能将在我们的店铺脚本中使用(产品导入):)
  • 第一次审核后我有一些问题:您能否发布“SHOW CREATE TABLE ms_data”的输出以获取表结构的详细信息?您是在使用带有 mysql 驱动程序或 mysqli 类的 PDO 吗? :parent 参数发生了什么?它永远不会绑定。可能发布 $this->db 实例的类也很有用。

标签: php mysql database import


【解决方案1】:

我看到了一个问题:

如果您使用此功能加载大量信息,您将需要很长时间才能结束。

您可以使用单个查询加载所有数据,代码如下:

<?php
public function import($data = '') {

   if (!isset($data)) {
      return array(
         'error' => "Error: no data"
      );    
   }

   $data_arr = json_decode($data, true);

   if (is_array($data_arr) && sizeof($data_arr)) {

         // Truncate DB table

         $sql   = 'TRUNCATE `ms_data`';
         $this->db->query($sql)->execute();

         $itemCount = count($data_arr);

         // Import data
         $sql       = 'INSERT INTO `ms_data` (
                     `id`, 
                     `name`, 
                     `parent`, 
                     `ordering`
                     )  VALUES ';

        for($i=1; $i <= $itemCount; $i++)
        {
            // Last item should not put comma after values. 
            if ($i == $itemCount)
            {
                $sql = $sql . "(?,?,?,?)"
            }
            else
            {
                $sql = $sql . "(?,?,?,?),"
            }
        }

        $stmt = $this->db->prepare($sql);

        $i = 1;
        foreach($data_arr as $d) {


             $stmt->bindParam($i++, $d['id'])
             ->bindParam($i++, trim($d['name']))
             ->bindParam($i++, $d['ordering']);
         }

         $stmt->execute();

         return array(
             'status' => 1,
             'message' => 'Data has been imported'
         );                 

    } else {

         return array(
            'error' => "Input is not array"
         ); 
    }
}       
?>

使用这种方式,您将在单个查询中插入所有行,这大大减少了执行时间,并且将是 atomic operation

【讨论】:

  • 请注意,这在非常大的数据集上也会失败。那是数千或数百万,具体取决于 MySQL 的 MAX_ALLOWED_PACKET 以及您设置的参数的大小。顺便说一下,上面的代码中有一些代码重复。改为:$sql = $sql . "(?,?,?,?)"; if ($i &lt; $itemCount) { $sql .= ','; }
【解决方案2】:

如果您有大量数据,您应该执行以下操作:

1) 创建一个用于加载数据的新表:CREATE TABLE new_data LIKE ms_data
2) 填充您认为合适的数据:即INSERT INTO new_data VALUES (?,?,?,?)
3)用新表替换旧表:RENAME ms_data TO old_ms_data, new_data TO ms_data。此操作是原子操作,因此它应该对其他用户不可见。
4)清理,删除旧表:DROP TABLE old_ms_data

CREATE TABLEDROP TABLERENAME TABLE 都会导致隐式提交,因此您不能将其作为单个事务执行,但由于 RENAME TABLE 替换“ms_data”中的数据的性质,这仍然是原子的。

请注意,如果您对临时表使用静态名称(例如“new_data”),则不能同时执行两个加载过程。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-18
    • 1970-01-01
    • 2011-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多