テーブルの変更中に使用しているストアド プロシージャがあり、次のエラー メッセージで失敗します。
エラー 1206 (HY000): ロックの総数がロック テーブルのサイズを超えています
私は Web を調べて、ここと mysql フォーラムでエントリを見つけました。コンセンサスは、innodb_buffer_pool_size のサイズを大きくするか、1 回のアクションで追加/変更されるレコードの数を減らすことです。
残念ながら、innodb_buffer_pool_size を増やすオプションや機能がないため、アクションごとに変更されるレコードの数を減らそうとしています。しかし、それも失敗しています。
次の 2 つの列を持つ単純な時間分割テーブル event_notify_occurrence_cache がありました。
CREATE TABLE `event_notify_occurrence_cache` (
`timestamp` datetime NOT NULL,
`xml` text NOT NULL,
KEY `idx_timestamp` (`timestamp`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8
/*!50500 PARTITION BY RANGE COLUMNS(`timestamp`)
(PARTITION p2012_12_10__15_00_00UTC VALUES LESS THAN ('2012-12-10 16:00:00') ENGINE = InnoDB,
PARTITION p2012_12_10__16_00_00UTC VALUES LESS THAN ('2012-12-10 17:00:00') ENGINE = InnoDB,
...
...
...
これを変更して「イベント タイプ」列を作成する必要があります。ここで、イベント タイプは xml 列の文字列の一部です。「LIKE」検索を実行すると著しく遅いため、イベント タイプ用に別のインデックス付き列を追加します。以下に変更したいと思います。
CREATE TABLE `event_notify_occurrence_cache` (
`event_type_value` smallint(5) unsigned NOT NULL,
`timestamp` datetime NOT NULL,
`xml` text NOT NULL,
KEY `idx_timestamp` (`timestamp`),
KEY `idx_event_type_value` (`event_type_value`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
/*!50500 PARTITION BY RANGE COLUMNS(`timestamp`)
(PARTITION p2012_12_10__15_00_00UTC VALUES LESS THAN ('2012-12-10 16:00:00') ENGINE = InnoDB,
PARTITION p2012_12_10__16_00_00UTC VALUES LESS THAN ('2012-12-10 17:00:00') ENGINE = InnoDB,
...
...
これに一致するようにテーブルを変更すると、event_type_value 列に、期待どおりに、無効なイベント タイプ ゼロ (0) が入力されます。
これまでのところ、これはすべて機能します。
したがって、次のステップは、基本的に次のようなロジックを使用して、考えられるイベントの種類ごとにテーブルで一連の更新を行うことです。
UPDATE event_notify_occurrence_cache
SET event_type_value = 1
WHERE event_type_value = 0 AND xml LIKE "%<eventType>1</eventType>";
考えられるイベントの種類ごとにこれを繰り返します。
これは、最初の一致が約 201,827 レコードにヒットする、合計 9,110,000 レコードの 24 のパーティションがあるテスト ケースの 1 つでは失敗します。
特定のイベント タイプのすべてのエントリが完了するまでLIMIT
、句を含むステートメントを使用してループしようとしましたが、うまくいきません。UPDATE
最初に 5000 の制限で試しましたが、150,000 レコード後に失敗しました (デバッグ出力による)。次に、制限を 1000 に設定すると、152,000 レコードを超えると失敗します。その後の試行で、UPDATE
句をTRANSACTION
/のCOMMIT
ペアでラップしたところ、エラーになる前に 182,000 レコードになりました。
ロック テーブルがステートメントごとではなく、ストアド プロシージャごとにあるようです。
1 つのスタックオーバーフローの回答では、書き込み対象のテーブルをロックすることが提案されました。「LOCK TABLE」コマンドを使用してみましたが、それでも機能しませんでした。
サーバー バージョン 5.5.8-enterprise-commercial-advanced-log を使用しています
私のストアドプロシージャロジックの試みの1つの例は次のとおりです
....
OPEN etype;
REPEAT
FETCH etype INTO etype_name, etype_value;
IF done != 1 THEN
SET query_str :=
CONCAT('%<eventType>', etype_name, '</eventType>%');
SET changes_not_done := 1;
WHILE changes_not_done != 0 DO
SELECT CONCAT(CURRENT_TIMESTAMP(), ' ETYPE:', etype_name,
' CHANGES_NOT_DONE:', changes_not_done)
AS 'Debug Msg:';
UPDATE `UMS`.`event_notify_occurrence_cache`
SET event_type_value=etype_value
WHERE event_type_value=0 AND xml LIKE query_str
LIMIT 1000;
-- set changes_not_done to the number of rows modified by the
-- previous command. If it's zero, then we are done. If it's
-- non-zero then we have more to do.
SELECT ROW_COUNT() INTO changes_not_done;
END WHILE;
END IF;
UNTIL done = 1
END REPEAT;
CLOSE etype;
...
イベント タイプのテーブルがあり、それをループし、イベント タイプごとに通知キャッシュを検索して処理します。
よろしくお願いいたします。