ข้อมูลทั้งหมดต่อไปนี้ใช้กับ InnoDB
ฉันรู้สึกว่ารู้ความเร็วของ 3 วิธีที่แตกต่างกันเป็นสิ่งสำคัญ
มี 3 วิธีคือ
- INSERT: INSERT พร้อมการอัปเดตคีย์ ON DUPLICATE
- รายการ: ที่คุณทำการปรับปรุงสำหรับแต่ละระเบียนภายในการทำธุรกรรม
- กรณี: ในกรณีที่คุณ / เมื่อสำหรับแต่ละระเบียนที่แตกต่างกันภายในการปรับปรุง
ฉันเพิ่งทดสอบสิ่งนี้และวิธี INSERT นั้นเร็วขึ้น6.7เท่าสำหรับฉันกว่าวิธีการทำธุรกรรม ฉันลองชุดทั้ง 3,000 และ 30,000 แถว
วิธีการทำธุรกรรมยังคงต้องเรียกใช้แบบสอบถามแต่ละรายการซึ่งต้องใช้เวลาแม้ว่ามันจะแบทช์ผลลัพธ์ในหน่วยความจำหรือบางสิ่งบางอย่างในขณะที่ดำเนินการ วิธีการทำธุรกรรมก็ค่อนข้างแพงทั้งในการจำลองแบบและบันทึกแบบสอบถาม
แม้เลววิธีกรณีที่ถูก41.1xช้ากว่าวิธีการแทรก w / 30,000 ระเบียน (6.1 เท่าช้ากว่าการทำธุรกรรม) และช้าลง75xใน MyISAM วิธีการแทรกและกรณีทำลายแม้กระทั่งที่ ~ 1,000 ระเบียน แม้จะอยู่ที่ 100 บันทึกวิธีการ CASE นั้นเร็วกว่า
ดังนั้นโดยทั่วไปฉันรู้สึกว่าวิธี INSERT นั้นดีที่สุดและใช้งานง่ายที่สุด แบบสอบถามมีขนาดเล็กและอ่านง่ายขึ้นและใช้แบบสอบถามเพียงหนึ่งคำเท่านั้น สิ่งนี้ใช้กับทั้ง 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 interpreter overhead
<?
//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).';');
}