Все следующее относится к InnoDB.
Я чувствую, что знание скорости 3 различных методов очень важно.
Есть 3 метода:
- INSERT: INSERT с ON DUPLICATE KEY UPDATE
- СДЕЛКА: где вы делаете обновление для каждой записи в транзакции
- СЛУЧАЙ: В каком случае вы / когда для каждой отдельной записи в ОБНОВЛЕНИИ
Я только что проверил это, и метод INSERT был для меня в 6,7 раза быстрее, чем метод TRANSACTION. Я примерил набор из 3000 и 30000 строк.
Метод TRANSACTION по-прежнему должен запускать каждый отдельный запрос, который занимает время, хотя и выполняет результаты в памяти или что-то еще во время выполнения. Метод TRANSACTION также довольно дорог в журналах репликации и запросов.
Хуже того, метод CASE был в 41,1 раза медленнее, чем метод INSERT, с 30 000 записей (в 6,1 раза медленнее, чем TRANSACTION). И в 75 раз медленнее в MyISAM. Методы INSERT и CASE не превышают 1000 записей. Даже при 100 записях метод CASE БЫСТРО быстрее.
В общем, я считаю, что метод INSERT является лучшим и простым в использовании. Запросы меньше и их легче читать, и они занимают только 1 запрос действия. Это относится как к InnoDB, так и к MyISAM.
Бонусные вещи:
Решение задачи не по умолчанию поля INSERT, чтобы временно отключить соответствующие режимы SQL: SET SESSION sql_mode=REPLACE(REPLACE(@@SESSION.sql_mode,"STRICT_TRANS_TABLES",""),"STRICT_ALL_TABLES","")
. Обязательно сохраните sql_mode
первый, если вы планируете его вернуть.
Что касается других комментариев, которые я видел, что, скажем, auto_increment увеличивается с использованием метода INSERT, похоже, это имеет место в InnoDB, но не в MyISAM.
Код для запуска тестов выглядит следующим образом. Он также выводит файлы .SQL для удаления накладных расходов интерпретатора php
<?
//Variables
$NumRows=30000;
//These 2 functions need to be filled in
function InitSQL()
{
}
function RunSQLQuery($Q)
{
}
//Run the 3 tests
InitSQL();
for($i=0;$i<3;$i++)
RunTest($i, $NumRows);
function RunTest($TestNum, $NumRows)
{
$TheQueries=Array();
$DoQuery=function($Query) use (&$TheQueries)
{
RunSQLQuery($Query);
$TheQueries[]=$Query;
};
$TableName='Test';
$DoQuery('DROP TABLE IF EXISTS '.$TableName);
$DoQuery('CREATE TABLE '.$TableName.' (i1 int NOT NULL AUTO_INCREMENT, i2 int NOT NULL, primary key (i1)) ENGINE=InnoDB');
$DoQuery('INSERT INTO '.$TableName.' (i2) VALUES ('.implode('), (', range(2, $NumRows+1)).')');
if($TestNum==0)
{
$TestName='Transaction';
$Start=microtime(true);
$DoQuery('START TRANSACTION');
for($i=1;$i<=$NumRows;$i++)
$DoQuery('UPDATE '.$TableName.' SET i2='.(($i+5)*1000).' WHERE i1='.$i);
$DoQuery('COMMIT');
}
if($TestNum==1)
{
$TestName='Insert';
$Query=Array();
for($i=1;$i<=$NumRows;$i++)
$Query[]=sprintf("(%d,%d)", $i, (($i+5)*1000));
$Start=microtime(true);
$DoQuery('INSERT INTO '.$TableName.' VALUES '.implode(', ', $Query).' ON DUPLICATE KEY UPDATE i2=VALUES(i2)');
}
if($TestNum==2)
{
$TestName='Case';
$Query=Array();
for($i=1;$i<=$NumRows;$i++)
$Query[]=sprintf('WHEN %d THEN %d', $i, (($i+5)*1000));
$Start=microtime(true);
$DoQuery("UPDATE $TableName SET i2=CASE i1\n".implode("\n", $Query)."\nEND\nWHERE i1 IN (".implode(',', range(1, $NumRows)).')');
}
print "$TestName: ".(microtime(true)-$Start)."<br>\n";
file_put_contents("./$TestName.sql", implode(";\n", $TheQueries).';');
}