2011-09-13 168 views
2

我必須在mysql數據庫中更新2M * 2rows。mysql更新很慢 - 有沒有更快的方法來更新數據?

所有的信息都在一個文件中,我使用php進行處理。 我得到一個數組中的信息,然後使用

UPDATE processed 
SET number1=$row[1], number2=$row[2], timestamp=unix_timestamp() 
where match (id) against ('\"$id\"' IN BOOLEAN MODE) limit 1 

這是工作推動它在數據庫中 - 但這需要很長洙......

我有一個索引(初級)(ID) 。

我試圖使用其他(id)這是全文索引(我使用Myisam) - 它更慢。

由於我的數據庫非常大,而且mysql必須通過一切才能找到正確的更新行,所以每更新需要幾秒鐘..這意味着需要幾天來處理我的更新!

有沒有更快的方法來做到這一點? 如果我切換到innodb會更快嗎? (即使不是這樣,我猜在更新過程中它可能會很酷,但我的整個桌子不會被鎖定)。

由於number1 & number2是數字,我雖然將所有(id)必須更新到相同的數字 - 會更快嗎?

有沒有辦法調整mysqld,以便number1,number2 & id colums會留在RAM中,使訪問/更新更快?

任何想法是值得歡迎的,因爲我完全失去了... :)

編輯:添加一個示例代碼,這樣就可以理解我的處境:

foreach ($data_rows as $rows) { 
    $row=explode(":", $rows); // $row[0] info 
          // $row[1] new number1 
          // $row[2] new number2 

$query = $db->query("select * from processed where match (info) against ('\"$info\"' IN BOOLEAN MODE) limit 1"); 

    while ($line = $query->fetch_object()) 
{ 
    $data[$line->hash]['number1']=$line->number1; 
    $data[$line->hash]['number2']=$line->number2; 
    $id=$line->id; 
    } 

    if (is_array($data[$info]))  { // Check if we have this one in the database. 
    // If the number is correct, no need to update. 
    if (($data[$info]['number1'] != $row[1]) && ($data[$info]['number2'] != $row[2])) { 
$db->query("UPDATE processed SET number1=$row[1], number2=$row[2], timestamp=unix_timestamp() where id=$id"); 
print "updated - $info - $row[1] - $row[2]\n"; 
               } 
        } 
else { 
print "$info not in database\n"; 
    } 
       } 

瑪:

再次
CREATE TABLE `processed` (
    `id` int(30) NOT NULL AUTO_INCREMENT, 
    `timestamp` int(14) DEFAULT NULL, 
    `name` text, 
    `category` int(2) DEFAULT '0', 
    `subcat` int(2) DEFAULT '0', 
    `number1` int(20) NOT NULL, 
    `number2` int(20) NOT NULL, 
    `comment` text, 
    `hash` text, 
    `url` text, 
    PRIMARY KEY (`id`), 
    FULLTEXT KEY `name` (`name`), 
    FULLTEXT KEY `hash` (`hash`) 
) ENGINE=MyISAM AUTO_INCREMENT=1328365 DEFAULT CHARSET=utf8; 
/*!40101 SET character_set_client = @saved_cs_client */; 

編輯:

ANALYZE TABLE processed;確實幫助了很多改進的我0時。 (新指標!)

將在另一個表&加我的資料,怎麼加入更新:)

+1

1. innodb不支持全文。 2.爲什麼您將'id'字段設置爲全文列的一部分? (它應該是一個正常的整數字段?) – ajreal

+0

如果這需要很長時間,那麼索引肯定有問題。請張貼您的表格定義。 (處理DESCRIBE的輸出) – Cfreak

+0

@Cfreak:'+ ------------------ + ---------- + ------ + ----- + --------- + ---------------- + |字段|類型|空| Key |默認|額外| + ------------------ + ---------- + ------ + ----- + ----- ---- + ---------------- + | id | int(30)| NO | PRI | NULL | auto_increment | | number1 | int(20)| NO | | NULL | | | number2 | int(20)| NO | | NULL | | |評論|文字|是| | NULL | | | hash |文字|是| MUL | NULL | |' –

回答

1

您正在執行2M * 2個UPDATE命令。這需要一段時間...

我會建議您將文件內容轉儲到臨時表,然後運行一個UPDATE命令。

更新

下面是你運行單個加入UPDATE

UPDATE processed 
inner join DumpTable on processed.id = DumpTable.id 
SET number1=DumpTable.value1 , number2=DumpTable.value2, timestamp=unix_timestamp() 
+0

如果我將整個文件轉儲到數據庫中,那麼我將如何運行一個'UPDATE'命令來將所有內容添加到正確的位置? –

+0

謝謝。將嘗試。這聽起來是更有效地做事情的好選擇。 –

0

嘛)你應該總是消毒你的數據 -

sprintf("UPDATE processed 
     SET number1=%d, number2=%d, timestamp=unix_timestamp() 
     WHERE match (id) 
     AGAINST ('%d' $id IN BOOLEAN MODE) limit 1", 
     mysql_real_escape_string($row[1]), 
     mysql_real_escape_string($row[2]), 
     mysql_real_escape_string($id) 
); 

此外,如果你切換到InnoDB它可能會稍微快一些,但是,對於很多人來說這是一個更好的選擇,因爲你不鎖定整個表格如果您正在爲每個UPDATE工作,只鎖定正在更新的行。

所以這是最definatly一些思考,請閱讀以下鏈接:http://www.kavoir.com/2009/09/mysql-engines-innodb-vs-myisam-a-comparison-of-pros-and-cons.html

+0

即使mysql_real_escape_string已經在php代碼中被轉義了,它會更好嗎?關於InnoDB這聽起來很有趣,因爲它似乎在我的情況下它不會受到傷害(如果我停止使用全文搜索) –

+0

我個人總是將mysql_real_escape_string所有我推送到數據庫甚至從數據庫中提取的東西。我還建議創建數據庫的備份,創建一個新的InnoDB並嘗試一下。 它有什麼危害? :) – DarkMantis