0

2 つの mysql テーブルがあります。

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

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

接続するクライアントがたくさんあり、特定のサーバーに対して1つのジョブを取り、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ですか?

私が考えることができる 1 つのことは、クエリを 2 つに分割することです。最初にサーバー名を id に変換してからクエリのみを実行しますtbl_jobsが、実際のアプリケーションでは、1 つのサーバー名に多くの ID を含めることができます (奇妙に聞こえることはわかっていますが、ここでは説明のために私のアプリケーションを簡略化しています)。したがって、2 番目のクエリにtbl_jobsは準備済みステートメントが必要です。

もっとエレガントな解決策があると確信しています。

システム:

  • Amazon RDS 上の MySQL 5.1.67
  • すべてのテーブルは InnoDb です
  • インデックスを持っていますtbl_jobs.server_id
4

1 に答える 1

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 $$
于 2013-01-10T10:51:07.987 に答える