2013-06-13 63 views
2

我有包含4000行,我想將它們插入到mysql的.txt文件,這裏有它做同樣的事情兩種方法,第一種方法是簡單的編碼是這樣的:php bindParam()加速批量插入嗎?

$start = microtime(true); 
foreach($b as $k=>$v){//$b is an array of 4,000 elements 
    $db->exec("INSERT INTO siji (en,cn) VALUES ('$v[0]','$v[1]')"); 
} 
echo microtime(true)-$start;//116 sec. 

第二種方法是使用PDO :: bindParam(),我知道對於重複的SQL查詢,使用bindparam()是一個好習慣,因爲每個查詢之間的唯一區別是它們的值,所以我編碼像這樣:

$start = microtime(true); 
$stmt = $db->prepare('INSERT INTO siji (en,cn) VALUES (:en,:cn)'); 
$stmt->bindParam(':en',$en); 
$stmt->bindParam(':cn',$cn); 
foreach($b as $k=>$v){//$b is an array of 4,000 elements 
    $en = $v[0]; 
    $cn = $v[1]; 
    $stmt->execute();// 
} 
echo microtime(true)-$start;//127 sec. 

第二種方法比第一種方法更快,結果並不像我想的那樣,可能任何人都會告訴我bindparam()真的能夠加速批量插入嗎?或者在使用bindparam()時可能會出錯?

+0

考慮使用PDO事務:http://php.net/manual/en/pdo.begintransaction.php – Lidor

回答

1

你還沒有指定你正在使用的數據庫服務器,所以我會假定MySQL,因爲它是最常見的。

要直接回答您的問題:答案是肯定的,PDO的prepare函數應該使用DB的Prepared Statements功能,當運行一批類似的查詢時,結果會更快。

但是,特別是對於MySQL PDO驅動程序,它默認模擬準備好的語句,而不是實際正確使用它們。

這意味着默認情況下,在PDO對象內部,它基本上與第一個代碼示例完全一樣,可以手動構建SQL字符串。

我不知道爲什麼這是默認行爲(也許與舊的mySQL版本存在兼容性問題?),但爲了防止它並強制PDO正確使用Prepared Statements,您需要禁用此選項。

你可以做到這一點,如下所示:

$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES,false); 

試一下,看看會發生什麼。順便說一句,如果你的4000行的.txt文件碰巧是CSV或其他常規格式的文件,你可以使用MySQL的內置LOAD DATA INFILE函數,它可以通過單個查詢將整個文件加載到數據庫中。這總是比通過在PHP中循環相同的查詢4000次所能實現的任何事情都要快得多更多。 (其他DB具有類似的功能)。

+0

我添加了$ db-> setAttribute(PDO :: ATTR_EMULATE_PREPARES,false);但執行時間沒有顯着變化,也許我必須嘗試其他事情,如交易 – user7031

0

我有包含4000行的.txt文件,我想將它們插入到MySQL

使用LOAD DATA INFILE那麼,如果您關心的速度

此外,100 4000插入的秒數太多了。你必須將你的插入包裝在交易中,或者考慮將你的innodb配置成less paranoid mode

0

第二種方法surposed比第一個更快,結果並不像我以爲是,雖然,任何人都可以告訴我不bindparam()真正加快批量插入?

它實際上更快。不一定需要像發佈的那樣簡單的查詢。

這有點像基準MySQL與PostgreSQL。如果您使用MyISAM表執行測試,而這些表執行的是不重要的非併發選擇,那麼您的基準測試可能會決定MySQL優於Postgres。但是,如果你用六個連接運行數百個併發查詢,你的基準測試可能會告訴你一個完全不同的故事。

你的情況,你正在準備一個平凡的插入。解析SQL是微不足道的;確定最佳查詢計劃同樣微不足道。準備聲明的好處是非常渺茫。另一方面,如果你在每個插頁上有幾個不平凡的觸發器,你可能會得到一個完全不同的故事。

關於真準備和模擬準備還有一些事情要說。有時候,準備好的陳述並不能給你一個最佳的計劃。考慮此查詢:

select * from foo order by bar limit ? 

如果您準備在上面,計劃不能決定是否使用上欄的指標 - 如果酒吧是足夠低,它會讓意義;如果它很龐大,你可能會抓取整個表並將其排序。所以計劃者會選擇後者的計劃。相反,如果直接發送最終查詢,計劃人員將擁有所有需要的元素來決定使用同一個索引是否對該特定值有意義。換句話說,仿真準備偶爾會更適用於僅運行一次的查詢或用於簡單查詢的查詢。

哦,不要忘記把整個事情包裝成一個單獨的事務。這將顯着加快速度。