MySQL 对 MyISAM、InnoDB 批量插入经验总结

今天做个功能遇到数据批量插入的问题,测试了下几种情况下的简单对比,虽然测试方式不全面但也能得出基本结果了,就不浪费时间了。

批量插入测试的几个要点:

  1. 引擎:MyISAM 和 InnoDB
  2. SQL 语法:

    a: INSERT INTO TABLE filed1, filed2 … VALUES (val1 , val2 , …)

    b: INSERT INTO TABLE filed1, filed2 … VALUES (val1 , val2 , …) , (val1 , val2 , …) , (val1 , val2 , …) …

  3. InnoDB 驱动下启用事务和不启用事务
  4. 驱动方式:PDO 使用 预编译占位符方式


具体过程没什么好写的,直接总结下好了:

1. 速度最快的方式。



引擎:选择引擎的话,当然是 MyISAM 了;



语法:上面 SQL 语法 b 方式。一个 INSERT 语句后面 VALUES 部分跟上 N 个要插入的每行数据;


我用的是PDO占位符方式,所有 VALUES 后面全是问号形式占位符。

对于占位符,PDO 里面貌似最大数量为 65535 个,所以根据 插入语句的字段数量不通,每次插入的行数也就不一样了。

我测试的例子中,每行有 17 个字段有占位符,所以一次最多录入 3855 行数据,如果不用占位符的话好像没什么限制的吧(我没试过)

2. 容易失误的地方

使用 InnoDB 引擎,却用普通方式批量插入,没有启动事务进行提交

特别是使用上面 SQL 语法 a 方式,每一行都带上字段名,插入4000行左右用了144秒,慢的要死。

加上事务或者使用 SQL语法 b 方式两者速度相差不多,则速度缩减到 0.5 秒左右,相差 288 倍。


3. 下面贴上代码

源码:不能直接用的 看看意思明白就行

    /**
     * 生成插入数据的字段以及对应占位符并绑定数据
     * @param null|array $data
     * @param int $rows
     * @return string
     */
    protected function getInsertFieldValues(array $data, $rows) {
        $data && $this->data($data);
        $data = $this->getData();
        $fields = $holders = $bind = array();
        foreach ($data as $k => $v) {
            $fields[] = $k;
            $holders[] = ‘?‘;
        }
        $vals = ‘ , ( ‘ . implode(‘ , ‘, $holders) . ‘ )‘;
        return ‘( ‘ . implode(‘ , ‘, $fields) . ‘ ) VALUES ‘. ltrim(str_repeat($vals, $rows), ‘ ,‘);
    }
    /**
     * 将多行数据共用一个 INSERT 语句进行批量插入
     * 速度最快, 但插入失败时只能大范围的元素块, 而不能精确到某一行
     * 其次, 每次插入占位符总数不能超过 65535 个, 程序将自动判断占位符数量并对列表进行分页插入
     * 该方法对 innoDB 引擎和 MyISAM 引擎速度相差不大
     * @param array $list
     * @return int|array 成功则返回行数, 失败返回包含错误部分的所有元素(但不能精确到具体某一行)
     * @throws Exception
     */
    protected function addAllMoreInRow(array $list) {
        $rowsNum = count($list);
        if (isset($list[0])) $row = $list[0];
        else {
            $row = array_shift($list);
            array_unshift($list, $row);
        }
        // 每一行的占位符数量
        $holdersNum = count($row);
        // 计算对数组分割每块最大元素数量
        $chunkSize = min(array(50000, floor(65535/$holdersNum)));
        // 获得批量插入语句模版并进行预编译
        $query[0] = ‘INSERT INTO‘;
        $query[1] = $this->getTable();
        $query[2] = $this->getInsertFieldValues($row, $chunkSize);
        $this->prepare($query);
        // 保存之前已设置的绑定数据
        $defaultBind = $this->bind ? $this->bind : array();
        // 对数组按页分组
        $list = array_chunk($list, $chunkSize, true);
        // 最后一页索引
        $last = count($list) - 1;
        // 将数组分成多块单独绑定数据再进行按页插入
        foreach ($list as $p=>$block) {
            // 最后一页因数量不一致需重置预编译模版
            if ($p == $last) {
                $this->reset();
                $query[2] = $this->getInsertFieldValues($row, count($block));
                $this->prepare($query);
            }
            $this->bind = $defaultBind;
            foreach ($block as $r=>$data) {
                foreach ($data as $k=>$v) {
                    $this->bind[] = $v;
                }
            }
            $result = $this->execute($this->bind);
            if (! $result) return $block;
        }
        $this->reset();
        return $rowsNum;
    }

版权声明:本文为博主原创文章,未经博主允许不得转载。http://blog.csdn.net/zhouzme

时间: 2024-08-04 01:32:35

MySQL 对 MyISAM、InnoDB 批量插入经验总结的相关文章

MYSQL开发性能研究——批量插入的优化措施

一.我们遇到了什么问题 在标准SQL里面,我们通常会写下如下的SQL insert语句. INSERT INTO TBL_TEST (id) VALUES(1);   很显然,在MYSQL中,这样的方式也是可行的.但是当我们需要批量插入数据的时候,这样的语句却会出现性能问题.例如说,如果有需要插入100000条数据,那么就需要有100000条insert语句,每一句都需要提交到关系引擎那里去解析,优化,然后才能够到达存储引擎做真的插入工作. 正是由于性能的瓶颈问题,MYSQL官方文档也就提到了使

Mysql千万级别数据批量插入,性能提高

-----------------------------------------------------------方式1 ---------------------------------------------------------------------------------------- 第一步:配置my.ini文件 文件中配置 bulk_insert_buffer_size=120M 或者更大 将insert语句的长度设为最大. Max_allowed_packet=1M Net

java mysql大数据量批量插入与流式读取分析

总结下这周帮助客户解决报表生成操作的mysql 驱动的使用上的一些问题,与解决方案.由于生成报表逻辑要从数据库读取大量数据并在内存中加工处理后在 生成大量的汇总数据然后写入到数据库.基本流程是 读取->处理->写入. 1 读取操作开始遇到的问题是当sql查询数据量比较大时候基本读不出来.开始以为是server端处理太慢.但是在控制台是可以立即返回数据的.于是在应用 这边抓包,发现也是发送sql后立即有数据返回.但是执行ResultSet的next方法确实阻塞的.查文档翻代码原来mysql驱动默

MySQL的MyISAM InnoDB 区别简单笔记!

MyISAM InnoDB 区别 一.MYISAM .frm:表结构 .MYD:表数据 .MYI:表索引   二.INNODB .frm:表结构 .idb:表空间 .opt:字符集和排列规则 MyISAM 和 InnoDB 讲解 InnoDB和MyISAM是许多人在使用MySQL时最常用的两个表类型,这两个表类型各有优劣,视具体应用而定.基本的差别为:MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持.MyISAM类型的表强调的是性能,其执行数度比InnoDB类型更快.     M

MySQL ??? ??(Heap, MyIsam, InnoDB...) ????

alter table ? ???? ??? ??? ???? ??(Heap, MyIsam, InnoDB...)? ???? ??? ???. ?? ??? ?? ??? ??? ?? ??? ?? ????? ???? ????. [???? ?? ????] ??) alter table [????] type=[??? ???] "??? ???"?? Heap, MyIsam, InnoDB ... ??? ????^^??? MyIsam?? ??? mytable?

mysql 中 myisam innodb 的区别有哪些

MyISAM InnoDB 构成上的区别: 每个MyISAM在磁盘上存储成三个文件.第一个文件的名字以表的名字开始,扩展名指出文件类型. .frm文件存储表定义. 数据文件的扩展名为.MYD (MYData). 索引文件的扩展名是.MYI (MYIndex). 基于磁盘的资源是InnoDB表空间数据文件和它的日志文件,InnoDB 表的大小只受限于操作系统文件的大小,一般为 2GB事务处理上方面: MyISAM类型的表强调的是性能,其执行数度比InnoDB类型更快,但是不提供事务支持 InnoD

用python操作mysql数据库(之批量插入数据)

#!/usr/bin/env python # -*- coding: utf-8 -*- import MySQLdb #建立连接 conn = MySQLdb.connect(host='127.0.0.1',user='root',passwd='1qaz#EDC',db='test_db') cur = conn.cursor() #对数据进行操作 li = [('tanzhenx','shaoguan'),('huangmengdie','shaoguan')] #定义一个列表,列表中

使用JDBC在MySQL数据库中快速批量插入数据

使用JDBC连接MySQL数据库进行数据插入的时候,特别是大批量数据连续插入(10W+),如何提高效率呢? 在JDBC编程接口中Statement 有两个方法特别值得注意: void addBatch() throws SQLException Adds a set of parameters to this PreparedStatement object's batch of commands. int[] executeBatch() throws SQLException Submits

mysql妙用:批量插入记录,遇到重复记录则为自动更新

在更新大量数据时可能同时遇到两个问题: 如果每条更新执行一次sql性能很低,也容易造成阻塞: 批量更新时又有可能遇到主键重复的问题 使用 ON DUPLICATE KEY UPDATE 一条sql解决批量更新和主键重复问题(id为主键) INSERT INTO mytable(id,pid,ele,anim)  VALUES (?,?,?,?),(?,?,?,?),(?,?,?,?) ON DUPLICATE KEY UPDATE pid=VALUES(pid),ele=VALUES(ele)