我有一个cron作业,更新数据库中的大量行。有些行是新的,因此插入,有些是现有的更新,因此更新。MySQL:使用插入和更新而不是插入重复键更新会更快吗?
我用重复键更新插入整个数据并把它在一个调用来完成。
可是 - 我真的知道哪些行是新的和更新,所以我还可以做的插入和更新seperately。
将分离该插入和更新具有优势,在性能方面?这背后的机制是什么?
谢谢!
我有一个cron作业,更新数据库中的大量行。有些行是新的,因此插入,有些是现有的更新,因此更新。MySQL:使用插入和更新而不是插入重复键更新会更快吗?
我用重复键更新插入整个数据并把它在一个调用来完成。
可是 - 我真的知道哪些行是新的和更新,所以我还可以做的插入和更新seperately。
将分离该插入和更新具有优势,在性能方面?这背后的机制是什么?
谢谢!
你说
其实,我知道这行是新的和更新,所以我还可以做的插入和更新seperately。
如果你知道,没有击中即插入的,哪些是更新数据库,然后运行正确的语句是比执行INSERT更快... ON DUPLICATE KEY ...
的插入都将不要更快; UPDATE会更快,因为您不必首先尝试INSERT。
这要看存储引擎使用的,MyISAM的是在选择和插入,因为它可以做他们同时很不错,但它锁定了整个表的时候写了这么不更新那么好。您如何尝试对其进行基准测试,并找出哪种方法需要更长的时间?
从性能的角度来看,不同的是在语句的数量 - 在内存中的数据集去在网络和解析查询是什么正在大多数的时间,这就是为什么有它在单个语句有助于提高性能。既然你知道哪些需要插入vs更新,我不相信你会看到任何性能差异。如果Update使用WHERE语句来记录要更新的记录的ID,则应该看不到性能差异。
您是否在为每条记录使用个别语句?您可能需要查看批量更新的加载数据infile。上次尝试时我们获得了一些表现(一年)。
在使用ON DUPLICATE密钥更新我的测试是在比使用插入/更新慢的平均1.3×。 这是我的测试:
INSERT/UPDATE(54.07秒)
<?php
$mtime = microtime();
$mtime = explode(" ",$mtime);
$mtime = $mtime[1] + $mtime[0];
$starttime = $mtime;
?>
<?php
set_time_limit(0);
$con = mysql_connect('localhost', 'root', '');
mysql_select_db('test');
for ($i = 1; $i <= 1000; $i = $i + 2)
{
mysql_query("
INSERT INTO users
VALUES(NULL, 'username{$i}', 'email.{$i}', 'password{$i}')
");
}
for ($i = 1; $i <= 1000; $i++)
{
if ($i % 2 == 0)
{
mysql_query("
INSERT INTO users
VALUES(NULL, 'username{$i}', 'email.{$i}', 'password{$i}')
");
}
else
{
mysql_query("
UPDATE users
SET (username = 'username{$i}', email = 'email{$i}', password = 'password{$i}')
");
}
}
?>
<?php
$mtime = microtime();
$mtime = explode(" ",$mtime);
$mtime = $mtime[1] + $mtime[0];
$endtime = $mtime;
$totaltime = ($endtime - $starttime);
echo "This page was created in ".$totaltime." seconds";
?>
ON DUPLICATE KEY UPDATE(70.4秒)
<?php
$mtime = microtime();
$mtime = explode(" ",$mtime);
$mtime = $mtime[1] + $mtime[0];
$starttime = $mtime;
?>
<?php
set_time_limit(0);
$con = mysql_connect('localhost', 'root', '');
mysql_select_db('test');
for ($i = 1; $i <= 1000; $i = $i + 2)
{
mysql_query("
INSERT INTO users
VALUES(NULL, 'username{$i}', 'email.{$i}', 'password{$i}')
");
}
for ($i = 1; $i <= 1000; $i++)
{
mysql_query("
INSERT INTO users
VALUES({$i}, 'username{$i}', 'email.{$i}', 'password{$i}')
ON DUPLICATE KEY UPDATE
username = 'username{$i}', email = 'email{$i}', password = 'password{$i}'
");
}
?>
<?php
$mtime = microtime();
$mtime = explode(" ",$mtime);
$mtime = $mtime[1] + $mtime[0];
$endtime = $mtime;
$totaltime = ($endtime - $starttime);
echo "This page was created in ".$totaltime." seconds";
?>
我得到另一个完全不同的结果。 INSERT ON DUPLICATE比UPATE快!
MySQL版本
innodb_version 5.6。13
PROTOCOL_VERSION 10
版本5.6.13-企业商业先进
version_compile_machine x86_64的
version_compile_os osx10.7
结果
SELECT udf_CreateCounterID(0,CURRENT_DATE);
SELECT @update, @updateend, @updatediff, @insertupdate, @insertupdate_end, @insertupdatediff, @keyval, @countlmt;
@更新= 2013-09-12 17:32:27
@ updateend = 2013年9月12日17时33分01秒
@ updatediff = 34
@ =的insertUpdate 2013年9月12日17时32分00秒
@insertdate_end = 2013年9月12日17时32分27秒
@ insertupdatediff = 27
@ KEYVAL = 13
@ countlmt = 1000000
表
CREATE TABLE `sys_CounterID` (`exch_year` int(11) NOT NULL,
`nextID` int(11) NOT NULL,
PRIMARY KEY (`exch_year`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
测试功能
CREATE DEFINER=`root`@`localhost` FUNCTION `udf_CreateCounterID`(exchID SMALLINT, listyear DATE) RETURNS int(10) unsigned
BEGIN
DECLARE keyvalue INT UNSIGNED DEFAULT 0;
SET @countlmt = 1000000;
SET keyvalue = ((exchID % 512) << 9) + EXTRACT(YEAR FROM listyear) % 100;
SET @keyval = keyvalue;
SET @retVal = 0;
SET @count = @countlmt;
SET @insertupdate = SYSDATE();
WHILE @count > 0 DO
INSERT INTO `sys_CounterID`(`exch_year`,nextID)
VALUE(keyvalue, 1)
ON DUPLICATE KEY UPDATE
nextID = (@retVal := nextID + 1);
SET @count = @count - 1;
END WHILE;
SET @insertupdate_end = SYSDATE();
SET @insertupdatediff = TIMESTAMPDIFF(SECOND, @insertupdate,@insertupdate_end);
SET @count = @countlmt;
SET @update = SYSDATE();
WHILE @count > 0 DO
UPDATE sys_CounterID
SET nextID = (@retVal := nextID + 1)
WHERE exch_year = keyvalue;
SET @count = @count - 1;
END WHILE;
SET @updateend = SYSDATE();
SET @updatediff = TIMESTAMPDIFF(SECOND, @update,@updateend);
RETURN @retVal;
END
我会发出一个删除知行的,然后因为他们是我再次插入。只有当您没有影响其他表格的触发器或外键时才有效。 – Pentium10 2010-03-22 21:39:49
@Kevin Crowell我不理解你。我只在他没有的时候才提到这个作品。 – Pentium10 2010-03-22 22:14:49
也将使用“替换” - http://dev.mysql.com/doc/refman/5.1/en/replace.html – CheeseConQueso 2010-03-23 22:53:44