【问题标题】:Codeigniter's insert_batch() with thousands of inserts has missing recordsCodeigniter 的 insert_batch() 有数千个插入,缺少记录
【发布时间】:2025-12-27 17:35:10
【问题描述】:

我正在使用insert_batch() 将 10000+ 行大量插入数据库中的表中。我正在做一些测试,我注意到有时所有 10.000+ 行都被正确插入,但在某些情况下,我在表的总数中错过了 100+ 行。

我拥有的记录中的字段数据没问题,因为我在每次测试中都使用相同的数据,而且大多数时候我没有问题。例如,我尝试了 20 次将相同的数据插入到我的数据库中,并且在 19 次所有行都将正确插入,但在这一次我会错过 100 行或更多行。

insert_batch() 的函数如下:

protected function save_sms_to_database() {
    //insert_Batch
    $datestring = "%Y-%m-%d %h:%m:%s";
    $time = time();
    $datetime = mdate($datestring, $time);

    $this->date_sent = $datetime;

    foreach ($this->destinations as $k => $v) {
        $sms_data[$k] = array(
            'campaign_id' => $this->campaign_id,
            'sender_id' => $this->from,
            'destination' => $v,
            'token' => md5(time() . 'smstoken' . rand(1, 99999999999)),
            'message' => $this->body,
            'unicode' => $this->unicode,
            'long' => $this->longsms,
            'credit_cost' => $this->eachMsgCreditCost,
            'date_sent' => $this->date_sent,
            'deleted' => 0,
            'status' => 1,
            'scheduled' => $this->scheduled,
        );
    }

    $this->ci->db->insert_batch('outgoingSMS', $sms_data);
    if ($this->ci->db->affected_rows() > 0) {
        // outgoingSMS data were successfully inserted      
        return TRUE;
    } else {
        log_message('error', $this->campaign_id.' :: Could not insert sms into database');
        log_message('error', $this->ci->db->_error_message());
        return FALSE; // sms was not inserted correctly
    }
}

在这种情况下如何调试insert_batch()

我在 DB_active_rec.php 上进行了一些更改,以便在 insert_batch 期间进行一些日志记录,但到目前为止,我无法成功重现问题以查看问题所在。但就问题在开始时出现 2-3 次并且我没有对我的逻辑进行重大更改来修复它而言,我不能这样离开它,因为我不信任 codeigniter 的 insert_batch() 生产功能。

我还添加了 codeigniter 的 insert_batch() 函数:

    public function insert_batch($table = '', $set = NULL)
{
        $countz = 0;
    if ( ! is_null($set))
    {
        $this->set_insert_batch($set);
    }

    if (count($this->ar_set) == 0)
    {
        if ($this->db_debug)
        {
            //No valid data array.  Folds in cases where keys and values did not match up
            return $this->display_error('db_must_use_set');
        }
        return FALSE;
    }

    if ($table == '')
    {
        if ( ! isset($this->ar_from[0]))
        {
            if ($this->db_debug)
            {
                return $this->display_error('db_must_set_table');
            }
            return FALSE;
        }

        $table = $this->ar_from[0];
    }

    // Batch this baby
    for ($i = 0, $total = count($this->ar_set); $i < $total; $i = $i + 100)
    {

        $sql = $this->_insert_batch($this->_protect_identifiers($table, TRUE, NULL, FALSE), $this->ar_keys, array_slice($this->ar_set, $i, 100));

        //echo $sql;

        $this->query($sql);
                    $countz = $countz + $this->affected_rows();
    }

    $this->_reset_write();
            log_message('info', "Total inserts from batch:".$countz);

    return TRUE;
}

最后一个log_message() 与批处理中的总插入数也显示了问题,因为当我的插入数少于预期时,我在那里也得到了非预期数量的插入数。

我必须考虑其他方法才能将数千行插入到我的数据库中(不带或不带 codeigniter)。

有人对这类问题有任何线索吗?也许它与硬盘驱动器或系统内存不足有关?这是一台 1GB 内存的旧电脑。

编辑:根据要求,我在这里放了一个由 codeigniter 的 insert_batch() 函数生成的包含 9 行的示例 INSERT 语句

INSERT INTO `outgoingSMS` (`campaign_id`, `credit_cost`, `date_sent`, `deleted`, `destination`, `long`, `message`, `scheduled`, `sender_id`, `status`, `token`, `unicode`) VALUES ('279',1,'2013-08-02 02:08:34',0,'14141415151515',0,'fd',0,'sotos',1,'4d270f6cc2fb32fb47f81e8e15412a36',0), ('279',1,'2013-08-02 02:08:34',0,'30697000000140',0,'fd',0,'sotos',1,'9d5a0572f5bb2807e33571c3cbf8bd09',0), ('279',1,'2013-08-02 02:08:34',0,'30697000000142',0,'fd',0,'sotos',1,'ab99174d88f7d19850fde010a1518854',0), ('279',1,'2013-08-02 02:08:34',0,'30697000000147',0,'fd',0,'sotos',1,'95c48b96397b21ddbe17ad8ed026221e',0), ('279',1,'2013-08-02 02:08:34',0,'306972233469',0,'fd',0,'sotos',1,'6c55bc3181be50d8a99f0ddba1e783bf',0), ('279',1,'2013-08-02 02:08:34',0,'306972233470',0,'fd',0,'sotos',1,'d9cae1cbe7eaecb9c0726dce5f872e1c',0), ('279',1,'2013-08-02 02:08:34',0,'306972233474',0,'fd',0,'sotos',1,'579c34fa7778ac2e329afe894339a43d',0), ('279',1,'2013-08-02 02:08:34',0,'306972233475',0,'fd',0,'sotos',1,'77d68c23422bb11558cf6fa9718b73d2',0), ('279',1,'2013-08-02 02:08:34',0,'30697444333',0,'fd',0,'sotos',1,'a7fd63b8b053b04bc9f83dcd4cf1df55',0)

这是一个完整的插入。

【问题讨论】:

  • 在这种情况下,我建议将记录插入循环而不是单个查询(insert_batch)。通过这种方式,您还可以调试您的查询。
  • 您能告诉我们正在运行的 SQL 查询吗?也许有些格式不正确?您是否考虑过使用大量 INSERT 声明?
  • @NiloySaha 我不能真正使用循环进行如此大量的插入,因为它会降低我的系统性能。尤其是在生产中,这将是灾难性的。当我在为插入开发时使用循环时,据我所知,我没有遇到任何问题,但我无法将这种逻辑用于如此大量的插入。
  • @FritsvanCampen ,大量插入语句是 codeigniter 用于 insert_batch 的语句,据我所知,它将每个语句的数量限制为每个插入语句 100 行。我将使用一个包含 9 行的插入语句来编辑帖子。

标签: php mysql codeigniter


【解决方案1】:

insert_batch() 试图完全避免您的问题 - 尝试插入大于 MySQL 配置为一次处理的数据。我不确定 MySQL 的选项是 max_allowed_packet 还是其他东西,但它的问题是它设置了字节数限制,而不是行数。

如果您要编辑 DB_active_rec.php、mysql_driver.php 或任何合适的...尝试更改 for() 循环中的 100 个计数。 50 应该是更安全的选择。

除此之外,仅供参考 - 如果您通过 insert_batch() 插入超过 100 行,affected_rows() 将不会返回正确的值,因此将其用作成功/错误检查是不可靠的。这是因为insert_batch() 一次插入您的数据 100 条记录,而affected_rows() 只会返回最后一个查询的数据。

【讨论】:

  • 感谢您的回答,对于 affected_rows(),如果您看到我对 DB_active_rec.php 所做的更改,我设法准确计算了使用 insert_batch 完成了多少次插入,而我得到的总计数是正确的在任何时候(我也可以用select count(*) 验证它)。我将尝试按照您所说的更改循环计数并在那里进行一些测试。如果一切顺利,我会接受你的回答:)
  • 您能分享一下您是如何解决这个问题的吗?
【解决方案2】:

这个问题的解决方法是,你需要进入目录/system/database/并打开文件DB_query_builder.php并更新

public function insert_batch($table, $set = NULL, $escape = NULL, $batch_size = 1000)

您可以设置需求的大小。

【讨论】: