解析优化MySQL插入方法的五个妙招

 更新时间:2013年06月14日 12:21:47   作者:  
本篇文章是对优化MySQL插入方法的五个妙招进行了详细的分析介绍,需要的朋友参考下

工作中遇到大概20万的数据插入操作,程序编完后发现运行超时,修改PHP最大执行时间到600,还是超时,检查超时前插入的数据条数推算一下,大概要处理40~60分钟才能插入完成,看来程序写的效率太低,得优化了。
测试电脑配置:
CPU:AMD Sempron(tm) Processor
内存:1.5G
语句如下:

复制代码 代码如下:

$sql = "insert into `test` (`test`) values ('$content')";
for ($i=1;$i<1000;$i++) {
mysql_query($sql);
}
mysql_unbuffered_query 运行三次执行时间分别为:
9.85321879387
9.43223714828
9.46858215332
mysql_query 执行时间分别为:
10.0020229816
9.61053204536
9.24442720413
本人目前为止认为最高效率方式如下:
$sql = "insert into `test` (`test`) values ('$content')";
for ($i=1;$i<999;$i++) {
$sql .= ",('$content')";
}
mysql_query($sql);
执行时间为:
0.0323481559753
0.0371758937836
0.0419669151306

INSERT语句的速度
插入一个记录需要的时间由下列因素组成,其中的数字表示大约比例:
连接:(3)
发送查询给服务器:(2)
分析查询:(2)
插入记录:(1x记录大小)
插入索引:(1x索引)
关闭:(1)
这不考虑打开表的初始开销,每个并发运行的查询打开。
表的大小以logN (B树)的速度减慢索引的插入。
加快插入的一些方法:
· 如果同时从同一个客户端插入很多行,使用含多个VALUE的INSERT语句同时插入几行。这比使用单行INSERT语句快(在某些情况下快几倍)。如果你正向一个非空表添加数据,可以调节bulk_insert_buffer_size变量,使数据插入更快。参见5.3.3节,“服务器系统变量”。
· 如果你从不同的客户端插入很多行,能通过INSERT DELAYED语句加快速度。参见13.2.4节,“INSERT语法”。
· 用MyISAM,如果在表中没有删除的行,能在SELECT语句正在运行的同时插入行。
· 当从一个文本文件装载一个表时,使用LOAD DATA INFILE。这通常比使用很多INSERT语句快20倍。
· 当表有很多索引时,有可能要多做些工作使得LOAD DATA INFILE更快些。使用下列过程:

有选择地用CREATE TABLE创建表。
执行FLUSH TABLES语句或命令mysqladmin flush-tables。
使用myisamchk --keys-used=0 -rq /path/to/db/tbl_name。这将从表中取消所有索引的使用。
用LOAD DATA INFILE把数据插入到表中,因为不更新任何索引,因此很快。
如果只想在以后读取表,使用myisampack压缩它。
用myisamchk -r -q /path/to/db/tbl_name重新创建索引。这将在写入磁盘前在内存中创建索引树,并且它更快,因为避免了大量磁盘搜索。结果索引树也被完美地平衡。
执行FLUSH TABLES语句或mysqladmin flush-tables命令。

请注意如果插入一个空MyISAM表,LOAD DATA INFILE也可以执行前面的优化;主要不同处是可以让myisamchk为创建索引分配更多的临时内存,比执行LOAD DATA INFILE语句时为服务器重新创建索引分配得要多。
也可以使用ALTER TABLE tbl_name DISABLE KEYS代替myisamchk --keys-used=0 -rq/path/to/db/tbl_name,使用ALTER TABLE tbl_name ENABLE KEYS代替myisamchk -r -q/path/to/db/tbl_name。使用这种方式,还可以跳过FLUSH TABLES。
· 锁定表可以加速用多个语句执行的INSERT操作:
LOCK TABLES a WRITE;
INSERT INTO a VALUES (1,23),(2,34),(4,33);
INSERT INTO a VALUES (8,26),(6,29);
UNLOCK TABLES;
这样性能会提高,因为索引缓存区仅在所有INSERT语句完成后刷新到磁盘上一次。一般有多少INSERT语句即有多少索引缓存区刷新。如果能用一个语句插入所有的行,就不需要锁定。
对于事务表,应使用BEGIN和COMMIT代替LOCK TABLES来加快插入。
锁定也将降低多连接测试的整体时间,尽管因为它们等候锁定最大等待时间将上升。例如:
Connection 1 does 1000 inserts
Connections 2, 3, and 4 do 1 insert
Connection 5 does 1000 inserts
如果不使用锁定,2、3和4将在1和5前完成。如果使用锁定,2、3和4将可能不在1或5前完成,但是整体时间应该快大约40%。
INSERT、UPDATE和DELETE操作在MySQL中是很快的,通过为在一行中多于大约5次连续不断地插入或更新的操作加锁,可以获得更好的整体性能。如果在一行中进行多次插入,可以执行LOCK TABLES,随后立即执行UNLOCK TABLES(大约每1000行)以允许其它的线程访问表。这也会获得好的性能。
INSERT装载数据比LOAD DATA INFILE要慢得多,即使是使用上述的策略。
· 为了对LOAD DATA INFILE和INSERT在MyISAM表得到更快的速度,通过增加key_buffer_size系统变量来扩大 键高速缓冲区。
INSERT语法
复制代码 代码如下:

INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
       [INTO] tbl_name [(col_name,...)]
       VALUES ({expr | DEFAULT},...),(...),...
       [ ON DUPLICATE KEY UPDATE col_name=expr, ... ]


复制代码 代码如下:

INSERT [LOW_PRIORITY | DELAYED | HIGH_PRIORITY] [IGNORE]
       [INTO] tbl_name
       SET col_name={expr | DEFAULT}, ...
       [ ON DUPLICATE KEY UPDATE col_name=expr, ... ]


复制代码 代码如下:

INSERT [LOW_PRIORITY | HIGH_PRIORITY] [IGNORE]
       [INTO] tbl_name [(col_name,...)]
       SELECT ...
       [ ON DUPLICATE KEY UPDATE col_name=expr, ... ]

一、DELAYED 的使用
使用延迟插入操作
DELAYED调节符应用于INSERT和REPLACE语句。当DELAYED插入操作到达的时候,
服务器把数据行放入一个队列中,并立即给客户端返回一个状态信息,这样客户
端就可以在数据表被真正地插入记录之前继续进行操作了。如果读取者从该数据
表中读取数据,队列中的数据就会被保持着,直到没有读取者为止。接着服务器
开始插入延迟数据行(delayed-row)队列中的数据行。在插入操作的同时,服务器
还要检查是否有新的读取请求到达和等待。如果有,延迟数据行队列就被挂起,
允许读取者继续操作。当没有读取者的时候,服务器再次开始插入延迟的数据行。
这个过程一直进行,直到队列空了为止。
几点要注意事项:
· INSERT DELAYED应该仅用于指定值清单的INSERT语句。服务器忽略用于INSERT DELAYED...SELECT语句的DELAYED。
· 服务器忽略用于INSERT DELAYED...ON DUPLICATE UPDATE语句的DELAYED。
· 因为在行被插入前,语句立刻返回,所以您不能使用LAST_INSERT_ID()来获取AUTO_INCREMENT值。AUTO_INCREMENT值可能由语句生成。
· 对于SELECT语句,DELAYED行不可见,直到这些行确实被插入了为止。
· DELAYED在从属复制服务器中被忽略了,因为DELAYED不会在从属服务器中产生与主服务器不一样的数据。
注意,目前在队列中的各行只保存在存储器中,直到它们被插入到表中为止。这意味着,如果您强行中止了mysqld(例如,使用kill -9)
或者如果mysqld意外停止,则所有没有被写入磁盘的行都会丢失。

二、IGNORE的使用
IGNORE是MySQL相对于标准SQL的扩展。如果在新表中有重复关键字,
或者当STRICT模式启动后出现警告,则使用IGNORE控制ALTER TABLE的运行。
如果没有指定IGNORE,当重复关键字错误发生时,复制操作被放弃,返回前一步骤。
如果指定了IGNORE,则对于有重复关键字的行,只使用第一行,其它有冲突的行被删除。
并且,对错误值进行修正,使之尽量接近正确值。
insert ignore into tb(...) value(...)
这样不用校验是否存在了,有则忽略,无则添加

三、ON DUPLICATE KEY UPDATE的使用
如果您指定了ON DUPLICATE KEY UPDATE,并且插入行后会导致在一个UNIQUE索引或PRIMARY KEY中出现重复值,则执行旧行UPDATE。例如,如果列a被定义为UNIQUE,并且包含值1,则以下两个语句具有相同的效果:
mysql> INSERT INTO table (a,b,c) VALUES (1,2,3)
       -> ON DUPLICATE KEY UPDATE c=c+1;

mysql> UPDATE table SET c=c+1 WHERE a=1;

如果行作为新记录被插入,则受影响行的值为1;如果原有的记录被更新,则受影响行的值为2。
注释:如果列b也是唯一列,则INSERT与此UPDATE语句相当:
mysql> UPDATE table SET c=c+1 WHERE a=1 OR b=2 LIMIT 1;

如果a=1 OR b=2与多个行向匹配,则只有一个行被更新。通常,您应该尽量避免对带有多个唯一关键字的表使用ON DUPLICATE KEY子句。

您可以在UPDATE子句中使用VALUES(col_name)函数从INSERT…UPDATE语句的INSERT部分引用列值。换句话说,如果没有发生重复关键字冲突,则UPDATE子句中的VALUES(col_name)可以引用被插入的col_name的值。本函数特别适用于多行插入。 VALUES()函数只在INSERT…UPDATE语句中有意义,其它时候会返回NULL。
示例:
复制代码 代码如下:

mysql> INSERT INTO table (a,b,c) VALUES (1,2,3),(4,5,6)
       -> ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);
本语句与以下两个语句作用相同:
mysql> INSERT INTO table (a,b,c) VALUES (1,2,3)
       -> ON DUPLICATE KEY UPDATE c=3;
mysql> INSERT INTO table (a,b,c) VALUES (4,5,6)
       -> ON DUPLICATE KEY UPDATE c=9;

当您使用ON DUPLICATE KEY UPDATE时,DELAYED选项被忽略。

相关文章

  • MySQL正确修改最大连接数的3种方案

    MySQL正确修改最大连接数的3种方案

    这篇文章主要给大家介绍了关于MySQL正确修改最大连接数的3种方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03
  • 超详细教你怎么升级Mysql的版本

    超详细教你怎么升级Mysql的版本

    今天教各位小伙伴怎么升级Mysql的版本,文中非常详细的介绍了Mysql更换版本的操作,包括数据备份,卸载,安装.对不会升级的小伙伴们很有帮助哦,需要的朋友可以参考下
    2021-05-05
  • MySQL中DML添加数据insert的操作方法

    MySQL中DML添加数据insert的操作方法

    DML英文全称Data Manipulation Language数据操作语言,用来对数据库中表的数据记录进行增、删、改在实际开发过程中使用比较多,务必掌握操作,这篇文章主要介绍了MySQL中DML添加数据insert的操作方法,需要的朋友可以参考下
    2023-07-07
  • Centos6.9安装Mysql5.7.18步骤记录

    Centos6.9安装Mysql5.7.18步骤记录

    本文给大家详细介绍了Centos6.9安装Mysql5.7.18的步骤,非常不错,具有参考借鉴价值,需要的朋友参考下吧
    2017-06-06
  • 云服务器Ubuntu_Server_16.04.1安装MySQL并开启远程连接的方法

    云服务器Ubuntu_Server_16.04.1安装MySQL并开启远程连接的方法

    这篇文章主要介绍了云服务器Ubuntu_Server_16.04.1安装MySQL并开启远程连接的方法,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2018-02-02
  • mysql select语句操作实例

    mysql select语句操作实例

    这篇文章主要介绍了mysql select语句操作实例,本文给出了ORDER BY查询、GROUP BY查询、LIMIT查询、UNION等语句的实例,需要的朋友可以参考下
    2014-12-12
  • MySQL密码忘了怎么办?MySQL重置root密码方法

    MySQL密码忘了怎么办?MySQL重置root密码方法

    本文主要介绍Windows和Linux系统下忘记密码重置root密码的方法,需要的朋友可以参考下。
    2016-05-05
  • 详解MySQL事务的ACID如何实现

    详解MySQL事务的ACID如何实现

    事务(Transaction)是并发控制的基本单位,所谓的事务呢,它是一个操作序列,这些操作要么都执行,要么都不执行,它是一个不可分割的工作单位,本文给大家详细介绍了MySQL事务的ACID如何实现,需要的朋友可以参考下
    2023-10-10
  • windows下mysql 8.0.27 安装配置图文教程

    windows下mysql 8.0.27 安装配置图文教程

    这篇文章主要为大家详细介绍了windows下mysql 8.0.27 安装配置图文教程,文中安装步骤介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-06-06
  • MySQL多实例安装开机自启动服务配置过程

    MySQL多实例安装开机自启动服务配置过程

    这篇文章主要介绍了MySQL中,多实例安装开机自启服务配置的过程详细步骤,有需要的朋友可以借鉴参考下,希望可以有所帮助,感谢阅读
    2021-09-09

最新评论