[英]How to atomically move rows from one table to another?
我正在從數千個傳感器中收集讀數並將其存儲在MySQL數據庫中。 每秒有幾百次插入。 為了提高插入性能,我最初將這些值存儲到MEMORY緩沖區表中。 每分鍾運行一次存儲過程,該過程將插入的行從內存緩沖區移到永久表。
基本上,我想在存儲過程中執行以下操作以將行從臨時緩沖區中移出:
INSERT INTO data SELECT * FROM data_buffer;
DELETE FROM data_buffer;
不幸的是,前一個命令不可用,因為數據收集過程在INSERT和DELETE之間的“ data_buffer”中插入了其他行。 因此,這些行將被刪除而不插入到“數據”表中。
如何使操作原子化或使DELETE語句僅刪除在前面的語句中已選擇並插入的行?
我希望以標准的方式執行此操作,如果可能的話,該方法可以在不同的數據庫引擎上運行。
由於性能開銷和存儲要求,我寧願不添加任何其他“ id”列。
我希望標准SQL或類似內容中有SELECT_AND_DELETE或MOVE語句...
我相信這會起作用,但會阻塞直到插入完成
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
BEGIN TRANSACTION;
INSERT INTO data (SELECT * FROM data_buffer FOR UPDATE);
DELETE FROM data_buffer;
COMMIT TRANSACTION;
如何獲得一個行ID,如何在插入之前獲取最大值,進行插入,然后刪除記錄<= max(id)
避免所有這些問題並保持快速運行的一種可能方法是使用兩個data_buffer
表(讓我們將它們data_buffer1
和data_buffer2
)。 當收集過程插入到data_buffer2
,您可以在data_buffer2
上進行insert
和delete
; 而不是切換,因此收集的數據將進入data_buffer2
,而數據將從data_buffer1
插入+刪除到data
。
這與@ammoQ的答案類似。 區別在於,您可以使計划過程中的表透明交換,而不必讓INSERTing進程弄清楚要寫入哪個表。
在計划的過程中使用RENAME交換表:
CREATE TABLE IF NOT EXISTS data_buffer_new LIKE data_buffer;
RENAME TABLE data_buffer TO data_buffer_old, data_buffer_new TO data_buffer;
INSERT INTO data SELECT * FROM data_buffer_old;
DROP TABLE data_buffer_old;
這是可行的,因為RENAME語句自動交換表,因此INSERTing進程不會因“找不到表”而失敗。 不過,這是特定於MySQL的。
我假設這些表是相同的,具有相同的列和主鍵? 如果是這樣,您可以在where子句中嵌套選擇...類似這樣:
DELETE FROM data_buffer
WHERE primarykey IN (SELECT primarykey FROM data)
這是MySQL特定的解決方案。 您可以使用鎖定來防止INSERTing進程在移動行時添加新行。
移動行的過程應如下所示:
LOCK TABLE data_buffer READ;
INSERT INTO data SELECT * FROM data_buffer;
DELETE FROM data_buffer;
UNLOCK TABLE;
在緩沖區中插入新行的代碼應進行如下更改:
LOCK TABLE data_buffer WRITE;
INSERT INTO data_buffer VALUES (1, 2, 3);
UNLOCK TABLE;
當鎖定到位時,INSERT進程顯然會阻塞。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.