2017-07-31 136 views
-1

我們需要每秒高於100個並發表的請求數。mySQL表更新併發性能

它是一個包含一堆唯一鍵碼的表格,它們在被請求時被分配一個request_guid。

該表包含整數主鍵,唯一鍵碼和空request_guid。

我們正在運行下面的查詢,它的工作原理與OK 10,000條記錄,但隨着100萬個+把它記錄嘎然而止,並在每次更新需要16+秒。

表:

(id INT 
keycode VARCHAR(50) 
request_guid VARCHAR(45) NULL) 

* Concurrant查詢:

UPDATE coupon 
SET request_guid = ? 
WHERE request_guid IS NULL 
ORDER BY RAND() LIMIT 1;* 

的RAND()的訂單正在使用,否則我們得到的鎖定問題,當在同一行正試圖同時更新。

任何人都可以想到一個更好的方法來做到這一點,以提高性能?鑰匙可能應該放在單獨的桌子上?

我希望以上是有道理的,謝謝你的幫助!

乾杯,

˚F

+0

您不需要在更新表格時執行排序,基本上,您正試圖將所有NULL request_guid更新爲特定值。你可以刪除'ORDER BY RAND()LIMIT 1'。 –

+0

這表明你沒有索引。在查詢上運行EXPLAIN PLAN並查找TABLE SCAN。如果你看到一個,你就知道你錯過了一個索引。這將不會掃描您的表添加行。爲什麼在插入行時不添加請求guid?我不明白更新的要求。 – duffymo

+0

如果您的代碼正常工作,並且您正在尋找更高效的代碼,那麼我會考慮更多的代碼審查問題。 –

回答

1

你就錯了!

首先,ORDER BY RAND()必須將整個表進行排序,所以這將是緩慢的窘況。

答案是欺騙。我將假設在設置這個特定的表時,事先知道唯一鍵碼的列表,並且一旦它被填充,就想隨機選擇鍵碼。所以讓我們從一個表「all_keycodes」開始。

Table all_keycodes 
keycode VARCHAR(50) 

現在,讓我們創建另一個表:

CREATE TABLE keycodes (
id INT PRIMARY KEY AUTO_INCREMENT, 
keycode VARCHAR(50) NOT NULL, 
UNIQUE(keycode) 
) 

...我們以隨機順序代碼填滿它,我們能做的只有這一次,設置系統時。

INSERT INTO keycodes (keycode) 
SELECT keycode FROM all_keycodes 
ORDER BY rand() 

現在這個表包含一個int主鍵,我們將用它來拉出鍵碼在它們的ID,已隨機的順序。

現在我們所要做的就是按照適合併發環境的快速方式按順序提供這些鍵碼。不幸的是,MySQL沒有序列,但它確實有表格!

CREATE TABLE used_keycodes( 
id INT PRIMARY KEY AUTO_INCREMENT, 
request_guid VARCHAR(45) NOT NULL, 
UNIQUE(request_guid) 
) 

現在,你可能會問,wtf?

簡單。當你想要求一個鍵碼,你這樣做:

INSERT INTO used_keycodes (request_guid) VALUES (your guid) 

並返回INSERT_ID給你另一個表的鍵碼。

這是併發的,安全的,它會很好地縮放。最重要的是,無論使用多少個鍵碼,找到一個尚未使用的鍵碼總是需要相同的時間,它只是一個INSERT。

您也可以將used_keycodes.id設置爲REFERENCE keycodes.id。

+0

感謝您花時間添加這樣一個深入的解決方案。會給出這個:)一個簡單的問題,如果我們在keycodes表中有多個密鑰批次的將來引入keybatch_id,我覺得這個解決方案將不再起作用?我相信我們現在可以忍受這一點,再次感謝:) –

+0

是的,這有點破解,因爲我使用auto_increment作爲原子共享計數器......但它是MySQL唯一的原子共享計數器。我相信MySQL可以像auto_increment一樣拆分PK(key_batch_id,counter),你必須檢查它。或者只是創建更多的表...使其更容易完成時刪除它們,而不是慢DELETE。 – peufeu

+0

這兩個表中的重大改進:擺脫'id'並將'UNIQUE'鍵推廣爲'PRIMARY KEY'。 –

0

一個簡單的方法是刪除ORDER BY並通過將隔離級別設置爲READ UNCOMMITTED(從而允許髒讀)來避免鎖定。

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED ; 
UPDATE coupon SET request_guid = ? WHERE request_guid IS NULL LIMIT 1; 
COMMIT ; 

這應該確保他們被允許閱讀WHERE子句中的非空,但未提交值更新不會在同一行競爭。

請注意,這不是一個非常時尚的解決方案,它只適用於您的數據庫支持READ UNCOMMITTED隔離級別(MySQL/InnoDB所做的)。

+0

謝謝@kayaman。這聽起來像一個簡單的答案。但是,這是否意味着如果更新同時發生,您最終可能會覆蓋對方的值? :) –

+0

請參閱我的答案的第3段。 – Kayaman

+0

謝謝,會給這個去吧! –