私はこのようなテーブルを持っています:
CREATE TABLE IF NOT EXISTS `jobs` (
`job_id` varchar(36) NOT NULL,
`job_status` varchar(30) NOT NULL,
`created_at` datetime NOT NULL,
`lease_date` datetime,
`priority` int NOT NULL,
PRIMARY KEY(`job_id`),
INDEX `job_status_priority_lease_date` (`job_status`, `priority`, `lease_date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
テーブルに対して実行する完全なクエリは次のようになります。
select * from jobs
where job_status="IN_PROGRESS"
and lease_date<"10minutesago"
order by
priority
limit 100
データベースをジョブキューとして実装しています。 10分はジョブタイムアウトのようなものです。既にタイムアウトしたジョブのみを処理したいと思います。仕事の優先順位が違うので注文しました。また、DBジョブキューをFIFOのように動作させたいので、インデックスにlease_date
を含めています。
結果を優先順位で並べ替えたいと思います。優先度0および1の結果の2つのチャンク。結果がlease_date
によって厳密に並べられている必要はありませんが、それらが私にとって十分な独自のチャンクで昇順である必要があります。例えば結果セット:
priority lease_date
0 2017-08-19
0 2018-09-20
1 2016-08-20
1 2018-10-20
私のインデックスはそれで十分ですか?クエリを最適化してインデックスを作成し、パフォーマンスを可能な限り向上させるにはどうすればよいですか?
_"10minutesago"
_とはNOW() - INTERVAL 10 MINUTE
ですか?
_order by priority DESC
_並べ替えのみpriority
。その中の順序は予測できません。昇順、降順、またはランダムに見える場合があります。
あなたのINDEX(job_status, priority, lease_date)
は_lease_date
_まで到達しません。 _where job_status="IN_PROGRESS"
_とmightが処理され、priority
の順序で行が処理されます。しかし、それだけです。
あなたcouldは_ORDER BY priority DESC, lease_date DESC
_と言いますが、_and lease_date < "10minutesago"
_はインデックスを使用しません。
したがって、最初に_=
_でテストされた任意の数の列を作成します。次にone range列を指定します。
(OPの編集後)
あなたの例はあなたが必要とすることを意味します
_ORDER BY priority ASC, lease_date ASC
_
効率の問題については...
WHERE
句には
_INDEX(job_status, lease_date) -- in this order; adding `priority` won't help
_
オプティマイザが_ORDER BY
_に集中することを好む場合は、
_INDEX(job_status, priority, lease_date) -- in this order
_
ノート:
job_status
_でテストされているため、_=
_が最初です。lease_date
_だけをタックすると、インデックス内のWHERE
全体を処理できるようになります。しかし、_ORDER BY
_を処理するための「ファイルソート」はまだ存在します。ORDER BY
_に集中するように誘惑すると、逆効果になる場合とそうでない場合があります。 _lease_date
_フィルターのためにスキップする必要があるデータの量によって異なります。テーブルに1000行ある場合は、両方のインデックスを追加するだけです。クエリは「十分に高速」になります。 100万行ある場合、難しい問題に直面しているため、キューイングメカニズムを再考する必要があります。インデックスをどう処理しても、間違ったインデックスが使用され、クエリの実行が非常に遅くなることがあります。システムに一時的な障害が発生すると、キューが文明的な数のエントリから膨大な数に散発的にジャンプする可能性があることに注意してください。
このテーブルが「キュー」であることを意味しますか?キュー内のアイテムを実行するのにどのくらい時間がかかりますか?それが「短い」時間である場合、「それをキューに入れないでください、それをしてください」。
priority
をWHEREに追加します
に変更した場合
_select * from jobs
where job_status = "IN_PROGRESS"
AND priority = 1
and lease_date < NOW() - 10 MINUTE
order by priority
limit 100
_
次に、これらのいずれかが最適になります。
_INDEX(job_status, priority, lease_date)
INDEX(priority, job_status, lease_date)
_
議論については my Cookbook を参照してください。
priority
ありとなしの混合がある場合は、次の2つを用意します。
_INDEX(job_status, lease_date),
INDEX(job_status, priority, lease_date)
_
オプティマイザーはそれらの間で選択します。