关于MySQL的load data infile

来源:互联网 发布:mastercamx9编程技巧 编辑:程序博客网 时间:2024/05/29 18:26

最近经常使用mysql的load data infile导入数据。查阅了相关资料记录下:

为什么load data infile 快

关于为什么Load data 会更快,查阅资料如下:
参考自:http://soft.chinabyte.com/database/386/12532886.shtml

较短的SQL 语句比较长的SQL 语句要快,因为它们涉及服务器方的分析较少,而且还因为将它们通过网络从客户机发送到服务器更快。这些因素中有一些似乎微不足道(特别是最后一个因素),但如果要装载大量的数据,即使是很小的因素也会产生很大的不同结果。我们可以利用上述的一般原理推导出几个关于如何最快地装载数据的实际结论:

  LOAD DATA(包括其所有形式)比INSERT 效率高,因为其成批装载行。索引刷新较少,并且服务器只需分析和解释一条语句而不是几条语句。

  LOAD DATA 比LOAD DATA LOCAL 效率更高。利用LOAD DATA,文件必须定位在服务器上,而且必须具有FILE 权限,但服务器可从磁盘直接读取文件。利用LOAD DATA LOCAL,客户机读取文件并将其通过网络发送给服务器,这样做很慢。

另外就是insert 的话,每运行一句,就更新一次索引,load 的话,全部执行完了再更新一次索引 (参考自http://www.debugease.com/mysql/281384.html)

究其根源主要是MySQL内部对于load 和 insert的处理机制不同.
Load的处理机制是:在执行load之前,会关掉索引,当load全部执行完成后,再重新创建索引.
Insert的处理机制是:每插入一条则更新一次数据库,更新一次索引.
补充:另外,load与insert的不同还体现在load省去了sql语句解析,sql引擎处理,而是直接生成文件数据块,所以会比Insert快很多.

摘自:http://www.itpub.net/thread-510339-1-1.html

即核心思想就是批量处理, insert也是可以提升的,处理方式就是进行批量insert

对于load infile只更新一次索引为不确认,查看http://dev.mysql.com/doc/refman/5.1/zh/sql-syntax.html#load-data 为执行该操作时为了提升性能可以使用ALTER TABLE...DISABLE KEYS关闭然后再执行,执行后再ALTER TABLE...ENABLE KEYS再次创建索引,创建索引的速度会更快。 查看http://dev.mysql.com/doc/refman/5.1/en/load-data.html 

E文如下:
If you use LOAD DATA INFILE on an empty MyISAM table, all nonunique indexes are created in a separate batch (as for REPAIR TABLE). Normally, this makes LOAD DATA INFILE much faster when you have many indexes. In some extreme cases, you can create the indexes even faster by turning them off with ALTER TABLE ... DISABLE KEYS before loading the file into the table and using ALTER TABLE ... ENABLE KEYS to re-create the indexes after loading the file. See Section 8.3.2.1, “Speed of INSERT Statements”.

多个client做insert。使用insert delayed 也可以加速插入
在Mysql中只支持MyISAM,MEMORY,ARCHIVE,BLACKHOLE的引擎。

 insert delayed into tableA() values(A,B,C);
原理:Insert是客户端发送sql到server,server做处理后将结果状态返回给客户端。使用Insert Delayed。是客户端发送sql后,server把其加入队列,马上返回状态给客户端。客户端可以继续执行别的操作了。而server等到空闲后马上插入这些队列中的数据。如果是多个client来插入数据的时候,每个Client的应用程序可以马上获得返回状态,进行之后的操作。而server端一旦空闲,就可以将整个队列作为一个block执行读写,这样IO的操作耗时就会降低。 或者说就是异步处理。问题是可能产生执行失败而无法知悉。(http://blog.sina.com.cn/s/blog_7e89c3f501012hzl.html)

注:这里有个疑问时如果是索引值更新一次,怎么解决load时的索引冲突问题呢

测试如下:

测试一为对于数据库已经存在的10000条记录,执行load

load data infile '1.txt' ignore into table test_table fields terminated by ',';
Query OK, 0 rows affected (1.04 sec)
Records: 100000  Deleted: 0  Skipped: 100000  Warnings: 0

测试二为对于数据库不存在记录,文件中有两条,但是这两条是重复的

 load data infile '1.txt' ignore into table test_table fields terminated by ',';
Query OK, 1 row affected (0.04 sec)
Records: 2  Deleted: 0  Skipped: 1  Warnings: 0

从测试结果看执行时还是会判断重复的,是不是先将数据插入,然后再根据建立索引时再处理呢

测试三为对于数据库不存在记录,文件中两条,但是两条id是重复的,但是内容不同,执行后查看数据库的内容是前面这条还是后面这条。

load data infile '1.txt' ignore into table test_table fields terminated by ',';

Query OK, 1 row affected (0.05 sec)
Records: 2  Deleted: 0  Skipped: 1  Warnings: 0

即执行时跳过了一条。

文件内容为:

1 100002,"hello 100001","test 100001"

2 100002,"hello 100002","test 100002"

select * from test_table where id = 100002;
+--------+----------------+---------------+
| id     | name           | attr          |
+--------+----------------+---------------+
| 100002 | "hello 100001" | "test 100001" |
+--------+----------------+---------------+

即为第一条的值

测试四:

还是有重复记录,但是执行load不忽略重复

      1 100003,"hello 100001","test 100001"
      2 100003,"hello 100002","test 100002"

load data infile '1.txt' into table test_table fields terminated by ',';
ERROR 1062 (23000): Duplicate entry '100003' for key 'index-1'

select * from test_table where id = 100003;
Empty set (0.00 sec)

即数据没有导入


load data infile使用时注意点

以下部分转载自:http://shanchao7932297.blog.163.com/blog/static/1363624201141135548221/

1)在客户端也可以向远程MySQL服务器执行 ‘load data‘ 命令,

      比如,客户端IP: 192.168.204.132
                 服务器IP: 192.168.204.131
      可以在192.168.204.132上,
      执行命令: mysql -h 192.168.204.131 -utest -ptest test -e'load local data infile "/opt/xxxxx.txt" into table loadtest;'
   
      条件:
      如果使用源码编译的MySQL,在configure的时候,需要添加参数:--enable-local-infile     
      客户端和服务器端都需要,否则不能使用local参数

2)load data infile 和 load local data infile 在   innodb和MyISAM 同步方面的区别
     对MyISAM引擎
          (1)对master服务器进行 ‘load’ 操作,
          (2)在master上所操作的load.txt文件,会同步传输到slave上,并在tmp_dir 目录下生成 load.txt文件
               master服务器插入了多少,就传给slave多少
          (3)当master上的load操作完成后,传给slave的文件也结束时,
               即:在slave上生成完整的 load.txt文件
               此时,slave才开始从 load.txt 读取数据,并将数据插入到本地的表中

     对innodb引擎
          (1)主数据库进行 ‘Load’ 操作
          (2)主数据库操作完成后,才开始向slave传输 load.txt文件,
               slave接受文件,并在 tmp_dir 目录下生成 load.txt 文件
               接受并生成完整的load.txt 后,才开始读取该文件,并将数据插入到本地表中

    异常情况处理:
    1)对MyISAM引擎
         当数据库执行load,此时如果中断:
         Slave端将报错,例如:
          ####################################################################
          Query partially completed on the master (error on master: 1053) and was aborted. 
          There is a chance that your master is inconsistent at this point. 
           If you are sure that your master is ok, 
           run this query manually on the slave and then restart the slave with SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1; 
          START SLAVE; . Query: 'LOAD DATA INFILE '/tmp/SQL_LOAD-2-1-3.data' IGNORE INTO  TABLE `test_1` 
          FIELDS  TERMINATED BY ',' ENCLOSED BY '' ESCAPED BY '\\' LINES TERMINATED BY '\n' (`id`, `name`, `address`)'
          ###########################################################################################
          按照提示,在slave服务器上:
          (1) 使用提示的load命令,将主服务器传输过来的load文件,在从服务器上执行
          (2)让从服务器跳过错误。set global sql_slave_skip_counter=1;
          (3)开启同步
     2)对Innodb引擎
          由于innodb是事务型的,所以会把load文件的整个操作当作一个事务来处理,
          中途中断load操作,会导致回滚。         
          与此相关的一些参数:
          max_binlog_cache_size----能够使用的最大cache内存大小。
                                                    当执行多语句事务时,max_binlog_cache_size如果不够大,
                                                    系统可能会报出“Multi-statement 
                                                     transaction required more than 'max_binlog_cache_size' bytes of storage”的错误。
           备注:以load data 来说,如果load的文件大小为512M,在执行load 的过程中,
                     所有产生的binlog会先写入binlog_cache_size,直到load data 的操作结束后,
                     最后,再由binlog_cache_size 写入二进制日志,如mysql-bin.0000008等。

                     所以此参数的大小必须大于所要load 的文件的大小,或者当前所要进行的事务操作的大小。

           max_binlog_size------------Binlog最大值,一般设置为512M或1GB,但不能超过1GB。
                                                    该设置并不能严格控制Binlog的大小,尤其是Binlog遇到一根比较大事务时,
                                                    为了保证事务的完整性,不可能做切换日志的动作,只能将该事务的所有SQL都记录进
                                                     当前日志,直到事务结束
           备注:有时能看到,binlog生成的大小,超过了设定的1G。这就是因为innodb某个事务的操作比较大,
                     不能做切换日志操作,就全部写入当前日志,直到事务结束。


另外其还有个可能是导致死锁:参见http://www.uml.org.cn/sjjm/201210302.asp 主要是存在自增id时
http://dev.mysql.com/doc/refman/5.1/zh/database-administration.html
http://dev.mysql.com/doc/refman/5.1/zh/sql-syntax.html#load-data

http://www.mysqlperformanceblog.com/2008/07/03/how-to-load-large-files-safely-into-innodb-with-load-data-infile/ : 关于加速innodb的load data infile的


0 0
原创粉丝点击