簡體   English   中英

如何將行從一個表原子移動到另一個表?

[英]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_buffer1data_buffer2 )。 當收集過程插入到data_buffer2 ,您可以在data_buffer2上進行insertdelete ; 而不是切換,因此收集的數據將進入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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM