ORDER BY id LIMIT 1
次のクエリで as を使用するよりも、特定の条件に一致する MySQL テーブルの最も古い行を更新するより高速な方法はありますか?
UPDATE mytable SET field1 = '1' WHERE field1 = 0 ORDER BY id LIMIT 1;
ノート:
- 主キーが
id
であり、 にもインデックスがあるとしfield1
ます。 - 1 つの行を更新しています。
- 厳密に最も古い行を更新するのではなく、条件に一致する最も古い行を更新しています。
- 一致する最も古い行、つまり最も低い行、つまり
id
FIFO キューの先頭を更新したいと考えています。
質問:
ORDER BY id
必要ですか?MySQL はデフォルトでどのように注文しますか?
実際の例
電子メール キューに使用される DB テーブルがあります。ユーザーに送信する電子メールをキューに入れる場合、行が追加されます。行は cron ジョブによって削除され、毎分実行され、その分で可能な限り処理され、行ごとに 1 つの電子メールが送信されます。
このアプローチをやめて、 GearmanやResqueなどを使用して電子メール キューを処理する予定です。しかし、それまでの間、キューの最も古いアイテムを処理のために効率的にマークする方法について質問があります。これは、ID が最小の行とも呼ばれます。このクエリは次のように機能します。
mysql_query("UPDATE email_queue SET processingID = '1' WHERE processingID = 0 ORDER BY id LIMIT 1");
ただし、スケーリングの問題により、mysql のスロー ログに頻繁に表示されます。テーブルに 500,000 行ある場合、クエリに 10 秒以上かかることがあります。問題は、このテーブルが最初に導入されて以来、非常に大きくなり、現在では 50 万行と 133.9 MiB のオーバーヘッドがあることです。たとえば、6000 行の新しい行をおそらく 1 日に 180 回 INSERT し、ほぼ同じ数を DELETE します。
スロー ログに表示されるクエリを停止するために、 を削除して、ORDER BY id
テーブル全体の大規模な並べ替えを停止しました。すなわち
mysql_query("UPDATE email_queue SET processingID = '1' WHERE processingID = 0 LIMIT 1");
...しかし、新しいクエリは常に最小の id を持つ行を取得するわけではありません (ただし、頻繁に取得します)。を使用する以外に、最も低い ID を持つ行を取得するより効率的な方法はありORDER BY id
ますか?
参考までに、これは電子メール キュー テーブルの構造です。
CREATE TABLE IF NOT EXISTS `email_queue` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`time_queued` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Time when item was queued',
`mem_id` int(10) NOT NULL,
`email` varchar(150) NOT NULL,
`processingID` int(2) NOT NULL COMMENT 'Indicate if row is being processed',
PRIMARY KEY (`id`),
KEY `processingID` (`processingID`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;