2011-08-03 67 views
5

Tôi đang thu thập các bài đọc từ vài nghìn cảm biến và lưu trữ chúng trong cơ sở dữ liệu MySQL. Có vài trăm lần chèn mỗi giây. Để cải thiện hiệu suất chèn, tôi lưu trữ các giá trị ban đầu vào một bảng bộ đệm MEMORY. Một lần một phút, tôi chạy một thủ tục được lưu trữ để di chuyển các hàng được chèn từ bộ nhớ đệm vào một bảng vĩnh viễn.Làm cách nào để di chuyển các hàng từ bảng này sang bảng khác?

Về cơ bản tôi muốn làm như sau trong thủ tục lưu trữ của tôi để di chuyển hàng từ bộ đệm tạm thời:

INSERT INTO data SELECT * FROM data_buffer; 
DELETE FROM data_buffer; 

Thật không may là trước đó là không sử dụng được vì quá trình thu thập dữ liệu chèn hàng bổ sung trong "data_buffer" giữa INSERT và DELETE ở trên. Vì vậy, những hàng đó sẽ bị xóa mà không bị chèn vào bảng "dữ liệu".

Làm cách nào để tôi có thể thực hiện phép toán nguyên tử hoặc tạo câu lệnh DELETE để chỉ xóa các hàng được CHỌN và CH INSN trong câu lệnh trước?

Tôi muốn thực hiện điều này theo cách tiêu chuẩn hoạt động trên các công cụ cơ sở dữ liệu khác nhau nếu có thể.

Tôi không muốn thêm bất kỳ cột "id" bổ sung nào vì yêu cầu lưu trữ và chi phí hoạt động.

Tôi muốn có SELECT_AND_DELETE hoặc tuyên bố MOVE trong SQL tiêu chuẩn hoặc một cái gì đó tương tự ...

+0

Bạn có thể cung cấp cấu trúc của bảng data_buffer không? –

+0

chắc: CREATE TABLE 'data_buffer' ( ' time' int (11) NOT NULL, 'sensor' smallint (6) NOT NULL, 'giá trị' nổi NOT NULL ) ENGINE = NHỚ DEFAULT CHARSET = latin1; – snap

+0

Tôi thực sự có một giải pháp cụ thể của MySQL nhưng có vẻ như tôi không được phép đăng nó trong phần câu trả lời trước 8 giờ. Tôi thực sự ghét những giới hạn trong stackoverflow ... – snap

Trả lời

1

Một cách có thể để tránh tất cả những vấn đề đó, và để ở nhanh, sẽ sử dụng hai bảng data_buffer (hãy gọi cho chúng data_buffer1data_buffer2); trong khi quy trình thu thập được chèn vào data_buffer2, bạn có thể thực hiện insertdelete trên data_buffer2; thay vì bạn chuyển đổi, dữ liệu được thu thập sẽ chuyển thành data_buffer2, trong khi dữ liệu được chèn + bị xóa từ data_buffer1 vào data.

+0

Cuối cùng tôi đã thực hiện một biến thể của giải pháp này: giải pháp RENAME TABLE mà tôi đã viết về câu trả lời của riêng tôi. Tuy nhiên vì nó dựa trên ý tưởng trong câu trả lời này, tôi chọn câu trả lời này là câu trả lời được chấp nhận của tôi. Sử dụng các bảng thay thế là giải pháp tốt nhất trong trường hợp của tôi vì không có thêm chi phí nào từ các cột id lưu giữ bản ghi và các chèn từ các cảm biến sẽ không bị chặn do khóa. – snap

3

Tôi tin rằng điều này sẽ làm việc nhưng sẽ chặn cho đến khi chèn được thực hiện

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; 
BEGIN TRANSACTION; 
INSERT INTO data (SELECT * FROM data_buffer FOR UPDATE); 
DELETE FROM data_buffer; 
COMMIT TRANSACTION; 
+0

Không. "SELECT FOR UPDATE" chỉ khóa các hàng được chọn nhưng không ngăn chặn INSERTing các hàng mới. – snap

+0

Tôi đã chỉnh sửa, .. hy vọng điều này sẽ giúp –

+0

Rất tiếc. Trên thực tế nó hoạt động với các bảng MEMORY (nếu được tạo thành một giao dịch đơn) vì chúng hiện chỉ hỗ trợ các khóa mức bảng. Tôi không muốn phụ thuộc vào các đặc tính của công cụ lưu trữ hiện tại, những người biết nếu phiên bản tiếp theo của MySQL thực hiện các khóa mức hàng cho các bảng bộ nhớ hoặc ai đó quyết định đặt bảng tạm thời trong bảng bộ nhớ NDB (hỗ trợ khóa mức hàng). – snap

0

tôi giả sử các bảng là giống hệt nhau , với cùng một cột và (các) khóa chính? Nếu đúng như vậy, bạn có thể chọn Ẩn mình bên trong một mệnh đề where ... một cái gì đó như thế này:

DELETE FROM data_buffer 
WHERE primarykey IN (SELECT primarykey FROM data) 
+0

Điều này sẽ làm việc nếu có bất kỳ "khóa chính". Hiện tại không có bởi vì nó không cần thiết cho các mục đích khác. Tuy nhiên tôi nghĩ rằng nó sẽ rất chậm vì có ** số lượng lớn ** hàng trong bảng * dữ liệu *. – snap

1

Làm thế nào về việc có một id hàng, nhận được giá trị tối đa trước khi chèn, hãy chèn và sau đó xóa các bản ghi < = max (id)

1

Đây là giải pháp tương tự như câu trả lời của @ ammoQ. Sự khác biệt là thay vì có quá trình INSERTing tìm ra bảng để ghi vào, bạn có thể hoán đổi các bảng một cách minh bạch trong thủ tục đã lên lịch.

Sử dụng RENAME trong thủ tục dự kiến ​​sẽ trao đổi bảng:

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; 

này hoạt động vì RENAME tuyên bố giao dịch hoán đổi các bảng nguyên tử, do đó quá trình chèn sẽ không thất bại với "không tìm thấy bảng". Đây là MySQL cụ thể mặc dù.

0

Đây là giải pháp cụ thể của MySQL. Bạn có thể sử dụng khóa để ngăn chặn các quá trình INSERTing thêm hàng mới trong khi bạn đang di chuyển các hàng.

Thủ tục trong đó di chuyển các hàng nên thực hiện như sau:

LOCK TABLE data_buffer READ; 
INSERT INTO data SELECT * FROM data_buffer; 
DELETE FROM data_buffer; 
UNLOCK TABLE; 

Mã mà chèn hàng mới trong bộ đệm nên được thay đổi như sau:

LOCK TABLE data_buffer WRITE; 
INSERT INTO data_buffer VALUES (1, 2, 3); 
UNLOCK TABLE; 

Quá trình INSERT sẽ rõ ràng là khối trong khi khóa được đặt đúng vị trí.

+2

Có vẻ như giải pháp này là sai, vì không thể sử dụng các BẢNG KHÓA trong các thủ tục lưu sẵn như được mô tả trong (http://dev.mysql.com/doc/refman/5.1/en/stored-program-restrictions.html). Thật không may tôi không thể downvote câu trả lời của riêng tôi. :) – snap

Các vấn đề liên quan