质量sql插入的优化

时间:2011-06-22 07:15:00

标签: mysql zend-framework pdo

我必须在数据库中插入100k +记录,我有一些内存问题。 $ _data是一个包含数据数组的数组。我甚至增加了内存大小但仍然遇到了问题

// VERSION 1
protected function save() {

    $memory_limit = ini_get('memory_limit');
    ini_set('memory_limit', '512M');

    $sql = "
        INSERT INTO table (
            c1,
            c2,
            c3,
            c4,
            c5,
            c6,
            c7,
            c7,
            c9,
            c10,
            c11             
        ) VALUES (?,?,?,?,?,?,?,?,?)
        ON DUPLICATE KEY UPDATE 
            c10 = VALUES(c10),
            c11 = VALUES(c10),
            c12 = VALUES(c12)
    ";
    $db = Zend_Registry::get('db');
    $stmt = new Zend_Db_Statement_Pdo($db, $sql);
    foreach($this->_data as $entry){
        $stmt->execute($entry);
    }
    unset($this->_data, $stmt, $sql);
    ini_set('memory_limit', $memory_limit);

第二个尝试在多插入中插入所有条目,但不是更好。

// VERSION 2
protected function save2(){
    $question_marks = str_repeat('?,', count($this->_data[0]));
    $question_marks = trim($question_marks, ',');
    $question_marks = str_repeat("($question_marks),", count($this->_data));
    $question_marks = trim($question_marks, ',');
    $sql = "
        INSERT INTO table (
            c1,
            c2,
            c3,
            c4,
            c5,
            c6,
            c7,
            c7,
            c9,
            c10,
            c11             
        ) VALUES $question_marks
        ON DUPLICATE KEY UPDATE 
            c10 = VALUES(c10),
            c11 = VALUES(c11),
            c12 = VALUES(c12)
        ;";
    $db = Zend_Registry::get('db');
    $stmt = new Zend_Db_Statement_Pdo($db, $sql);
    $insert_values = call_user_func_array('array_merge', $this->_data);
    $stmt->execute($insert_values);
    $affected_rows = $stmt->rowCount();
    if ($affected_rows){
        // @todo log    
    } 
    unset($this->_data);
    unset($stmt, $sql, $insert_values, $affected_rows, $question_marks);

列名不是原始名称。 有什么建议吗?


我将尝试将数据数组拆分为5k条目并批量执行插入操作。还试图看看如何修改mysql cnf中的max_allowed_pa​​cket有帮助。 同时我会感激任何建议。感谢

更新

在我的情况下将max_allowed_pa​​cket从16M修改为1024M有帮助,我确实在没有拆分数组的情况下进行插入。

3 个答案:

答案 0 :(得分:2)

你怎么知道你有内存问题而不是脚本执行超时?

无论如何,我会尝试使用简单的mysql_query

另外,请查看并确保读取数据的部分没有内存泄漏并准备插入数据库

答案 1 :(得分:1)

作为@Tudor Constantin答案的补充,当你提出其他建议时:

实际上,处理这种情况的一种方法是使用数据块,而不是使用100k +行的大_data数组(即使不讨论查询也是一个消耗大量可用内存的数组)。

您应该检查Zend_Memory是否存储包含所有100K行数据的数据结构。这将允许您管理包含所有行的虚拟对象,而不必将所有行都放在真正的PHP内存中。这可能会让您避免异步批处理。

然后每次运行有限行数的插入查询(以便查询字符串不会变得太大)。您可以使用您的2个代码示例,并且如在其他响应中所述,直接访问 mysql_query 可以防止来自Zend_Db或PDO的memleaks ..

如果您不使用mysql_query,请检查您是否在Db对象上激活了 Zend_Db_Profiler 。如果在每次请求后仍然看到一些内存泄漏,您可以尝试使用 Db 对象的Zend_Debug,并尝试查看某些历史数据是否未存储在某处(例如,过去的查询列表)。然后检查语句对象以及相同的事情。memory_get_usage函数调用可以帮助您调试泄漏。

我也会在foreach循环结束中尝试unset($entry);

答案 2 :(得分:0)

我认为您的问题是数组大小 - 与DB无关。你必须拆分$ this-> _data数组IMO。