2009-02-18 97 views
17

Tôi có một bảng MySQL nhiệm vụ để thực hiện, mỗi hàng có tham số cho một tác vụ duy nhất.
Có nhiều ứng dụng công nhân (có thể trên các máy khác nhau), thực hiện các tác vụ trong một vòng lặp.
Các ứng dụng truy cập cơ sở dữ liệu bằng cách sử dụng các API C gốc của MySQL.MySQL UPDATE và SELECT trong một lần

Để sở hữu một công việc, một ứng dụng làm điều gì đó như thế:

  • Tạo một id toàn cầu duy nhất (vì đơn giản, giả sử nó là một con số)

  • UPDATE tasks
    SET guid = %d
    WHERE guid = 0 LIMIT 1

  • SELECT params
    FROM tasks
    WHERE guid = %d

  • Nếu truy vấn cuối cùng trả về một hàng, chúng tôi sở hữu nó và có các thông số để chạy

Có cách nào để đạt được hiệu quả tương tự (ví dụ: 'sở hữu' một hàng và nhận các tham số của nó) trong một cuộc gọi đến máy chủ?

Trả lời

0

Tôi không biết về một phần cuộc gọi duy nhất, nhưng những gì bạn mô tả là một khóa. Khóa là một yếu tố thiết yếu của cơ sở dữ liệu quan hệ.

Tôi không biết các chi tiết cụ thể về khóa một hàng, đọc nó, và sau đó cập nhật nó trong MySQL, nhưng với một chút đọc của mysql lock documentation bạn có thể làm tất cả các loại thao tác dựa trên khóa.

Tài liệu postgres của locks có ví dụ tuyệt vời mô tả chính xác những gì bạn muốn làm: khóa bảng, đọc bảng, sửa đổi bảng.

+0

Khóa quá mức trong trường hợp này. Giải pháp trên sử dụng khóa nội bộ MySQL, do đó nhanh hơn nhiều. –

+0

Tôi thấy điểm của bạn .... bạn không cần khóa ở đây ... Tôi không biết một cuộc gọi nào. – Daniel

6

Bạn có thể tạo một thủ tục nào đó:

CREATE PROCEDURE prc_get_task (in_guid BINARY(16), OUT out_params VARCHAR(200)) 
BEGIN 

    DECLARE task_id INT; 

    SELECT id, out_params 
    INTO task_id, out_params 
    FROM tasks 
    WHERE guid = 0 
    LIMIT 1 
    FOR UPDATE; 

    UPDATE task 
    SET guid = in_guid 
    WHERE id = task_id; 

END; 

BEGIN TRANSACTION; 

CALL prc_get_task(@guid, @params); 

COMMIT; 
+1

Đã thử một cái gì đó tương tự. Tóm lại: các truy vấn SQL nguyên gốc nhanh hơn rất nhiều so với các thủ tục được lưu trữ. –

+3

Trong MySQL, không có nhiều khác biệt như trong Oracle. Bạn không thể làm điều đó trong một truy vấn đơn nào, nhưng thủ tục là một cuộc gọi đến máy chủ, giống như bạn đã hỏi. Với một chút nỗ lực, bạn có thể đặt BEGIN và COMMIT vào quy trình, nhưng tốt hơn là nên thực hiện từ ứng dụng, chỉ trong trường hợp. – Quassnoi

+0

Vì vậy, về cơ bản bạn đang nói rằng nó không phải là doable trong một cuộc gọi duy nhất. Tôi đã hy vọng một số hình thức INSERT INTO _tmp SELECT .. sẽ là vua đủ để cho phép một mysql_store_results() gọi vì nó cho phép mysql_affected_rows() –

1

Nếu bạn đang tìm kiếm một truy vấn duy nhất sau đó nó không thể xảy ra. Hàm UPDATE chỉ trả về số lượng các mục đã được cập nhật. Tương tự, hàm SELECT không thay đổi bảng, chỉ trả về giá trị.

Sử dụng quy trình sẽ thực sự biến nó thành một hàm duy nhất và có thể hữu ích nếu khóa là mối quan tâm của bạn. Nếu mối quan tâm lớn nhất của bạn là lưu lượng truy cập mạng (ví dụ: chuyển quá nhiều truy vấn) thì hãy sử dụng quy trình. Nếu bạn quan tâm là quá tải máy chủ (tức là: DB đang làm việc quá khó) thì chi phí phụ của một thủ tục có thể làm mọi thứ tồi tệ hơn.

+0

Mối quan tâm thực sự là quá tải máy chủ. Hy vọng của tôi là vì bản cập nhật đã 'tìm kiếm() ed' thành hàng, một lệnh SELECT sẽ dễ dàng hơn cho máy chủ trong cùng một câu lệnh. –

+2

Tôi cũng đang tìm kiếm một SELECT/UPDATE duy nhất và tìm thấy câu hỏi này. Tôi không muốn nó khóa, nhưng để sửa đổi cột LastAccessed trong hàng thành NOW() khi hàng được lấy ra – CashCow

+1

Hi Paulo, bạn có thể giải thích (hoặc đưa ra một liên kết) tại sao các thủ tục sẽ làm cho mọi thứ chậm hơn cho DB? Tôi nghĩ rằng SP là nhanh hơn: S – confiq

8

thử như thế này

UPDATE `lastid` SET `idnum` = (SELECT `id` FROM `history` ORDER BY `id` DESC LIMIT 1); 

mã ở trên làm việc cho tôi

+0

Làm việc cho tôi quá. Tôi thích phương pháp này. – Darius

+0

Cảm ơn !!!!!!!!! –

+0

Điều kiện cuộc đua này có an toàn không –

0
UPDATE tasks 
SET guid = %d, params = @params := params 
WHERE guid = 0 LIMIT 1; 

Nó sẽ trở lại 1 hoặc 0, tùy thuộc vào việc các giá trị đã được thay đổi một cách hiệu quả.

SELECT @params AS params; 

Điều này chỉ chọn biến từ kết nối.

Từ: here

1

Tôi gặp vấn đề tương tự. Thay vào đó, chúng tôi đã sử dụng PostreSQL và UPDATE ... RETURNING:

Điều khoản RETURNING tùy chọn làm cho UPDATE tính toán và trả về giá trị dựa trên mỗi hàng thực sự được cập nhật. Bất kỳ biểu thức nào sử dụng các cột của bảng và/hoặc các cột của các bảng khác được đề cập trong FROM, đều có thể được tính toán. Các giá trị mới (sau khi cập nhật) của các cột trong bảng được sử dụng. Cú pháp của danh sách RETURNING giống với cú pháp của danh sách đầu ra của SELECT.

Ví dụ: UPDATE 'my_table' SET 'status' = 1 WHERE 'status' = 0 LIMIT 1 RETURNING *;

Hoặc, trong trường hợp của bạn: UPDATE 'tasks' SET 'guid' = %d WHERE 'guid' = 0 LIMIT 1 RETURNING 'params';

Xin lỗi, tôi biết điều này không trả lời các câu hỏi với MySQL, và nó có thể không được dễ dàng chỉ cần chuyển sang PostgreSQL, nhưng đó là cách tốt nhất mà chúng tôi đã tìm được. Thậm chí 6 năm sau, MySQL vẫn không hỗ trợ UPDATE ... RETURNING. Nó có thể được thêm vào một lúc nào đó trong tương lai, nhưng bây giờ là MariaDB only has it for DELETE statements.

Sửa: Có một nhiệm vụ (ưu tiên thấp) để add UPDATE ... RETURNING support to MariaDB.

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