内存/时间高效的数据库输入

时间:2013-10-17 13:53:49

标签: php mysql

我有一个遍历数组的foreach循环。

在每个实例中,我将数组组织成一个查询字符串,并使用MySQLi将其添加到数据库中。

function storeProperties($data, $db) {
    foreach ($data['property'] as $property) {
        $query_string = "INSERT INTO table VALUES(..., ..., ...,)"
        $db->query($query_string);
        echo $db->error;
    }
}

我应该采取更好的方式吗?
显然,这种方法一个接一个地使用 n 数据库查询,因此这是内存密集型和时间密集型的。

有更好的方法吗? 我应该将每个查询连接成一个字符串并在for循环之外运行吗?

1 个答案:

答案 0 :(得分:0)

以下方法来自我的PDO主力,用于批量插入。它创建一个包含多个VALUES条目的INSERT语句。

将其用作

$db->bulkinsert(
    'tbl_my_tablename',
    array('fieldname_1','fieldname_2', 'fieldname_3'),
    array(
       /* rec1 */ array('r1f1', 'r1f2', 'r1f3'),
       /* rec2 */ array('r2f1', 'r2f2', 'r2f3'),
       /* rec3 */ array('r3f1', 'r3f2', 'r3f3')
    ));

请注意,该方法是来自复杂类定义的剪辑,此处使用的某些方法未包含在代码段中,尤其是$this->connect()(连接到PDO),$this->begin()(启动事务) ,$this->commit()$this->rollback(),以及类似于Apache Commons的Logging静态Log类; - )

但我确信这是你可能需要的。

    /**
     * Performs fast bulk insertion
     * Parameters:
     *     $tablename
     *     $datafields - non-assiciative array of fieldnames
     *                   or propertynames if $data is an array of objects
     *     $data       - array of either non-associative arrays (in the correct order)
     *                   or array of objects with property names matching the $datafields array
     */
    const MAX_BULK_DATA = 3000;
    public function bulkinsert($tablename, $datafields, &$data) {
        $result = 0;
        try {
            try {
                $this->connect();
                $datacount = count($data);
                // loop until all data has been processed
                $start = 0;
                $lastbinds = 0;
                $this->begin();
                while ($start < $datacount) {
                    $ins = array();
                    $bindscount = min(self::MAX_BULK_DATA, $datacount - $start);
                    if ($bindscount != $lastbinds) {
                        // prepare the binds
                        $binds = substr(str_repeat(',?', count($datafields)), 1);
                        $binds = substr(str_repeat(",($binds)", $bindscount), 1);
                        $lastbinds = $bindscount;
                    }
                    for ($go = $start, $last = $start + $bindscount; $go < $last; $go++) {
                        if (is_object($data[$go])) {
                            try {
                                foreach($datafields as $propname) {
                                    $rfl = new ReflectionProperty($data[$go], $propname);
                                    $rfl->setAccessible(true);
                                    $ins[] = $rfl->getValue($data[$go]);
                                }
                            }
                            catch(ReflectionException $e) {
                                throw new InvalidArgumentException('PDOCONNECT_ERR_SQL_UNKNOWN_PROPERTY', 0, $e);
                            }
                        }
                        else {
                            foreach($data[$go] as $value) {
                                $ins[] = $value;
                            }
                        }
                    }
                    $sql = sprintf('INSERT INTO %s (%s) VALUES %s', $tablename, join(',',$datafields), $binds);
                    Log::trace($sql);
                    $stmt = $this->pdo->prepare($sql);
                    $stmt->execute($ins);
                    $start = $last;
                    $result += $bindscount;
                }
                $this->commit();
            }
            catch(PDOException $e) {
                // do something with the exception if necessary
                throw $e;
            }
        }
        catch(Exception $e) {
            $this->rollback();
            throw $e;
        }
        return $result;
    }
}