2015-03-31 75 views
1

我試圖優化我的查詢,但是當我嘗試使用此查詢增加一些指標:ADD INDEX崩潰的MySQL

ALTER TABLE `user` ADD INDEX `last_activity_date` (`last_activity_date`); 

...崩潰我的MySQL服務器。我的意思是我的網站不再回應,我的查詢也沒有執行。我唯一的解決方案是重新啓動MySQL。這真的很煩人,因爲我有一個應用程序,數百名用戶顯然無法在崩潰時使用它。

我有一個MySQL日誌文件,但我沒有看到它的任何錯誤。你認爲這裏有什麼問題?難道是因爲有些用戶在添加索引時正在與數據庫交互?我使用InnoDB。

我有超過100.000記錄在user表看起來像:

CREATE TABLE `user` (
 `id` int(11) unsigned NOT NULL AUTO_INCREMENT, 
 `encrypt_id` varchar(255) DEFAULT NULL, 
 `register_date` datetime DEFAULT NULL, 
 `last_login_date` datetime DEFAULT NULL, 
 `username` varchar(255) DEFAULT NULL, 
 `password` varchar(255) DEFAULT NULL, 
 `email` varchar(255) DEFAULT NULL, 
 `banned` int(11) DEFAULT NULL, 
 `banned_reason` text, 
 `first_step_form` int(11) DEFAULT '0', 
 `status` int(11) DEFAULT NULL, 
 `referer` varchar(255) DEFAULT NULL, 
 `rank` int(11) DEFAULT NULL, 
 `fb_id` bigint(20) DEFAULT NULL, 
 `last_activity_date` datetime DEFAULT NULL, 
 PRIMARY KEY (`id`), 
 KEY `last_activity_date` (`last_activity_date`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 
+0

你可以發佈更多的信息,比如'user'表中的記錄數......一個SHOW CREATE TABLE就像'user''''語句嗎? – cerd 2015-03-31 19:50:27

+0

[在沒有表鎖定的情況下在一個巨大的mysql生產表上創建索引]的可能的重複(http://stackoverflow.com/questions/4244685/create-an-index-on-a-huge-mysql-production-table-without -table-locking) – 2015-03-31 19:52:12

+1

你是如何確定mysql崩潰的?你確定它不只是創建索引?用一張足夠大的表創建索引可能不僅僅是一眨眼的工作 - 我想我已經看到索引創建時間超過了30秒,所以我想它可能會更進一步。 – Kritner 2015-03-31 19:52:23

回答

2

假設你的網站非常活躍,你有100000個用戶,並且last_activity_date字段在每次用戶做某事(任何事情)時都會更新,那麼在該字段上應用索引可能會造成嚴重破壞。很多行可能需要花費幾分鐘時間才能應用,如果它不鎖定用戶,那麼索引永遠不會被創建,因爲在用戶不斷更改字段之前,它必須保持更新才能完成更新鎖定用戶以防止出現這種情況)。

像last_activity_date那樣對字段進行索引的唯一原因是針對它運行報表(例如,在過去30天內誰做了某些用戶的操作)或定期維護(禁用未在其中執行任何操作的用戶最近30天)。如果是這種情況,則最好創建一個輔助表並使用用戶表數據加載它,然後在該表上應用索引。您的報告不會針對實時數據 - 但您的報告不應該需要即時結果。每天更新一次次表可能不會很長 - 也許幾分鐘 - 並且它不會鎖定過程中的用戶。

+0

這是個好主意!我會嘗試使用用戶表的副本。 是的,我的網站非常活躍。我正在努力改進MySQL查詢,因爲我的服務器實際上非常慢。 – fraxool 2015-03-31 20:21:57

+0

冥想是一把雙刃劍。是的,他們在查詢時會提高性能 - 但更新時會影響性能。這是一個權衡。如果您的表格主要用於查詢,那麼添加索引將有所幫助 - 並且可能會有很大幫助。但是,如果您主要更新表 - 例如對last_activity_date進行了大量更改 - 那麼添加索引實際上會損害您的整體性能,因爲數據庫必須更新該索引。 – Russ 2015-03-31 20:25:41

2

如果你有一些使用表和ALTER TABLE用戶需要一點時間來執行,你是耗盡內存。這就是你在錯誤日誌中沒有看到任何東西的原因。您的內存不足,因爲您有一對多連接,因爲用戶在Alter表查詢運行時正在獲取元數據數據鎖定等待超時。

我不得不在表格上添加一個索引,並在前幾天在生產中創建了4200萬條記錄。花了10分鐘才完成。數據庫每分鐘讀取17k以上。我有PROCESSLIST開放和殺害任何查詢,其state顯示的元數據鎖定等待超時,這樣我就沒有能像這樣被確定我最糟糕的情況下下降:

innodb_buffer_pool_size + key_buffer_size + max_connections * (sort_buffer_size + read_buffer_size + binlog_cache_size) + max_connections * 2MB

如果你沒有這些參數設置正確並且達到最大連接數量時,可能會導致內存不足,導致服務器崩潰。

+0

大部分正確。儘管如此,最大化連接只與切斷內存相關。那些確實是兩種獨立的失敗模式。人們可能會感覺到MySQL服務器沒有響應(並且無法獲得新的連接),只是基於長時間運行的鎖定進程而達到max_connections閾值,而沒有接近內存分配限制(這通常會導致MySQL更頻繁地開始分頁到磁盤)。類似地,只是由於負載的高併發性而沒有達到最大連接,可能會遇到內存問題。 – 2015-03-31 20:13:46

+0

基於這種失敗的時間匹配「ADD INDEX」操作,我想冒險猜測OP由於連接堆棧而失敗。 – 2015-03-31 20:16:15

+0

同意。感謝您添加並澄清我的答案。我只是指出了一個潛在的問題,不是必要的原因。也就是說,如果參數設置不正確,並且由於鎖定等待超時而導致連接太多,則服務器可能會OOMing。 – BK435 2015-03-31 20:30:28