2013-01-10 27 views
0

我有兩個MySQL表:如何避免鎖定從SELECT中的所有表MySQL的INNER JOIN ... FOR UPDATE

tbl_jobs (
    id INTEGER PRIMARY KEY, 
    status ENUM("runnable", "running", "finished"), 
    server_id INTEGER 
) 

tbl_servers (
    is INTEGER PRIMARY KEY, 
    name VARCHAR(50) 
) 

我有很多連接的客戶端,需要一個工作了特定的服務器是runnable並將其設置爲running

這是我目前如何做到這一點(在存儲過程):

DELIMITER $$ 
CREATE PROCEDURE GET_JOB(serverName VARCHAR(50)) 
BEGIN 
    DECLARE jobId INTEGER DEFAULT NULL; 
    SELECT id FROM tbl_jobs j INNER JOIN tbl_servers s on j.server_id=s.id 
       WHERE j.state='runnable' AND s.server_name=serverName 
       ORDER BY job_id ASC LIMIT 1 
       INTO jobId FOR UPDATE; 
    IF IFNULL(jobId, 0) = 0 THEN 
     SELECT 0; 
    END IF; 
    UPDATE tbl_jobs SET state='running' WHERE job_id=jobId; 
    SELECT jobId; 
END $$ 

這工作得很好,當併發用戶的數量變大(數百個),我看到有一個大鎖擁擠進行tbl_servers表。我知道FOR UPDATE語句會鎖定所有的表,但我實際上使用tbl_servers作爲只讀表。

問題:如何在tbl_servers上避免鎖擁塞(即鎖定)?

我能想到的一件事是將我的查詢分成兩個 - 首先將服務器名稱轉換爲id,然後查詢tbl_jobs,但在我的真實應用程序中,一個服務器名稱可以有許多ID(我知道這聽起來很奇怪,但我只是簡單介紹了我的應用程序)。因此,tbl_jobs上的第二個查詢將需要準備好的語句。

我確定有一個更優雅的解決方案。

系統:在亞馬遜RDS

  • MySQL的67年5月1日
  • 所有的表的InnoDB
  • 我做對tbl_jobs.server_id
+0

你爲什麼需要'INNER JOIN'?在你的代碼中沒有真正的需要。 「servername」呢?你沒有在你的代碼中使用它,你爲什麼要通過這個?我不認爲,這是你的真實代碼 –

+0

固定使用'serverName' - 這是明顯的錯誤類型。謝謝!附:當然它不是一個真正的代碼。它是來自真實應用程序的一個摘錄,可以說明問題。 –

回答

1

這一個指標,應避免對錶的鎖定tbl_servers

DELIMITER $$ 
CREATE PROCEDURE GET_JOB(serverName VARCHAR(50)) 
BEGIN 
    DECLARE jobId INTEGER DEFAULT NULL; 

    -- get the server id's 
    CREATE TEMPORARY TABLE tmp_srvID 
    SELECT id 
    INTO srvID 
    FROM tbl_servers 
    WHERE name = serverName; 

    SELECT id 
    INTO jobId 
    FROM tbl_jobs 
    WHERE state='runnable' 

     AND server_id IN (SELECT id FROM tmp_srvID) 

    ORDER BY job_id ASC 
    LIMIT 1 
    FOR UPDATE; 

    DROP TABLE tmp_srvID; 

    IF IFNULL(jobId, 0) = 0 THEN 
     SELECT 0; 
    ELSE 
     UPDATE tbl_jobs SET state='running' WHERE job_id=jobId; 
     SELECT jobId; 
    END IF; 
END $$ 
+0

爲每個請求創建臨時表不會是一個很大的開銷嗎? –

+0

不,它不是一個很大的開銷,因爲臨時表建立在內存中 –