5

ORDER BY id LIMIT 1次のクエリで as を使用するよりも、特定の条件に一致する MySQL テーブルの最も古い行を更新するより高速な方法はありますか?

UPDATE mytable SET field1 = '1' WHERE field1 = 0 ORDER BY id LIMIT 1;

ノート:

  • 主キーがidであり、 にもインデックスがあるとしfield1ます。
  • 1 つの行を更新しています。
  • 厳密に最も古い行を更新するのではなく、条件に一致する最も古い行を更新しています。
  • 一致する最も古い行、つまり最も低い行、つまりidFIFO キューの先頭を更新したいと考えています。

質問:

  • ORDER BY id必要ですか?MySQL はデフォルトでどのように注文しますか?

実際の例

電子メール キューに使用される DB テーブルがあります。ユーザーに送信する電子メールをキューに入れる場合、行が追加されます。行は cron ジョブによって削除され、毎分実行され、その分で可能な限り処理され、行ごとに 1 つの電子メールが送信されます。

このアプローチをやめて、 GearmanResqueなどを使用して電子メール キューを処理する予定です。しかし、それまでの間、キューの最も古いアイテムを処理のために効率的にマークする方法について質問があります。これは、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;
4

5 に答える 5

3

これを読んでください:

于 2010-09-08T11:42:25.160 に答える
1

他のプロセスがテーブルをロックしているため、更新がタイムリーに完了しないようです-innodbの使用を検討しましたか?

于 2010-09-08T11:35:35.500 に答える
1

「遅い部分」はから来ていると思います

WHERE processingID = 0 

インデックスされていないため、遅いです。ただし、この列のインデックス作成 (IMHO) も正しくないようです。アイデアは、上記のクエリを次のように変更することです。

WHERE id = 0 

インデックスを使用するため、理論的にはどちらが高速になります。

id処理されていない行を含む別のテーブルを作成するのはどうですか? したがって、挿入は 2 回機能します。最初に実際のテーブルに挿入し、2 つ目はid「未処理のテーブル」に挿入します。処理部分も、その役割を 2 倍にする必要があります。id最初に「処理されていないテーブル」から取得してから削除します。加工部の第二の仕事はもちろん加工です。

もちろん、id「処理されていないテーブル」の列は、そのコンテンツにインデックスを付ける必要があります。選択と削除がより高速になるようにするためです。

于 2010-09-08T11:42:55.577 に答える
0

面白いことに、MySQL はデフォルトで ID 順の行を返しますが、リレーショナル理論で述べられているようにカジュアルな方法で返します (この動作が最新バージョンで変更されているかどうかはわかりません)。したがって、選択から取得する最後の行は、最後に挿入された行でなければなりません。もちろん、私はこの方法を使用しません。

あなたが言ったように、最善の解決策は、Resque や RabbitMQ などを使用することです。

揮発性ですが、そこに最新の ID を格納するよりもはるかに高速なインメモリ テーブルを使用するか、単に my_isam テーブルを使用して永続性を追加することができます。シンプルでパフォーマンスが速く、実装には少し時間がかかります。

于 2010-09-08T11:44:15.247 に答える