2017-12-03 14 views
0

"queue"という大きなテーブルがあります。今は1200万レコードあります。MySQLのパフォーマンス - 大きなテーブルからの選択と削除

CREATE TABLE `queue` (
    `id` int(11) unsigned NOT NULL AUTO_INCREMENT, 
    `userid` varchar(64) DEFAULT NULL, 
    `action` varchar(32) DEFAULT NULL, 
    `target` varchar(64) DEFAULT NULL, 
    `name` varchar(64) DEFAULT NULL, 
    `state` int(11) DEFAULT '0', 
    `timestamp` int(11) DEFAULT '0', 
    `errors` int(11) DEFAULT '0', 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `idx_unique` (`userid`,`action`,`target`), 
    KEY `idx_userid` (`userid`), 
    KEY `idx_state` (`state`) 
) ENGINE=InnoDB; 

複数PHP労働者(150)は、同時に、このテーブルを使用します。

レコードを選択し、選択したデータを使用してネットワーク要求を実行し、レコードを削除します。

selectクエリとdeleteクエリから実行時間が混在しています。 deleteコマンドはテーブルをロックしていますか?

このシナリオにはどのようなアプローチが最適でしょうか?

  1. 記録+ NETWORK要求は+記録に

  2. を削除]を選択し完了として(私もしたくない時からのcronを使用して完成したレコードをDELETE +記録+ NETWORK要求+ MARKレコードを選択大きなテーブル)。

注:キューは1分ごとに新しいレコードを取得しますが、INSERTクエリはここでは問題になりません。

何か助けていただければ幸いです。

+1

データベースをキューとして使用していて、複数のクライアントから作業している場合は、ロック競合が発生する可能性があります。データベースをキューとして使用しようとすると、誰もが苦労します。代わりに、データベースではなく、実際のメッセージキューソフトウェアを使用する必要があります。 ActiveMQやBeanstalkd、RabbitMQ、Resqueのようなもの。 –

+1

これは、特にクエリのパフォーマンスに関する部分を読むと参考になるでしょう。 http://meta.stackoverflow.com/a/271056/あなたの質問を編集して詳細を知りたいかもしれません。 –

答えて

1

「キューに入れないで、やってください」つまり、タスクがかなり速い場合は、単にアクションを実行し、キューに入れないほうがよいでしょう。データベースは良い待ち行列メカニズムを作っていません。

DELETE InnoDBテーブルをロックしません。しかし、あなたはDELETEと書くことはできません。あなたの実際のSQLを見て、それを改善するために働くことができます。

12Mレコード?それは大きなバックログです。どうしたの?

表がギガバイトにならないようにデータ型を縮小します。

  • actionは、可能な値のわずかなセットですか!これを1バイトのENUMまたはTINYINT UNSIGNEDに正規化します。
  • 同上state - 確かに4バイトコードは必要ありませんか?
  • すでにuseridで始まるインデックス(UNIQUE)があるので、INDEX(userid)の必要はありません。
  • stateの値がわずかである場合、インデックスは使用されません。エンキューとデキューのクエリを見て、そのインデックスを取り除く方法と、そのインデックスを「合成」する(有用な)方法について話し合うことができます。
  • MAX(id)の現在の値は何ですか?それはINT UNSIGNEDの約40億のあなたの現在の限界を超えることを脅かすのですか?
  • PHPはどのようにキューを使用しますか? InnoDBトランザクションを介してアイテムにハングアップしますか?これはどんな並列性にも勝るものです!または、それはstateに変更されますか?コードを見せてください。おそらくロック&のロックを解除することができます低侵襲。 1つの自動コミットされたUPDATEを実行して行を取得し、idを実行することが可能でなければなりません。それから、後で自動コミットされたDELETEを実行してください。
  • 保留中のアイテムを取得するための良好なインデックスはありません。もう一度、コードを見てみましょう。
  • 150は多くのように思われます - を少し実験しました?彼らはかもしれないはお互いにつまずいている。
  • スローログが有効になっていますか(long_query_timeの値が小さい)?もしそうなら、私は「最悪の」クエリが何であるか疑問に思います。このような状況では、その答えは驚くかもしれません。
+0

あなたの提案をありがとう。最初に、提案された変更のいくつかを実装しようとし、いくつかの結果が返ってきます。ありがとうございました! –

+0

*列アクションには7つの値しかありません *列状態には2つの可能な値があります *最大値(ID)は64577039です。 *作業者はuserid%150 = 0のタスクを実行します(作業と重複しません) *各操作に約2秒かかり、新しい操作が常にキューに追加されるので、巨大なキューを実行するためには非常に多くの作業者が必要です –

+0

I/Oバインドしていますか? CPUバインド?どちらも?労働者は同じ機械にいますか?もう1台のマシン?いくつかの他のマシン?あなたは2秒ごとに150アイテムを消費していますか?それがエンキューされる速度ですか? –

関連する問題