2

複数列のキー (member_id、visitor_id、month_visited) とより正確な日付を使用して、メンバー プロファイルの訪問を記録するために使用される非常に単純なテーブルがあります。month_visited は、「2013-10」のような CHAR(7) 列です。

新しい月ごとに、前月のデータを別のテーブルに圧縮してから削除したいと考えています。

私の要求は単純です:

DELETE FROM visits WHERE month_visited = '2013-10'

私の専用サーバーでは数分のように、これらの行を削除するには AGES かかります。シンプルなSELECT COUNT(*) FROM visits.

2013-10 には 180 万のエントリがあります。

しかし、それには年月がかかります。そして試してみると

EXPLAIN SELECT * FROM visits WHERE month_visited = "2013-10"

それは私に言います:

id  select_type table   type    possible_keys   key key_len ref rows    Extra
1   SIMPLE  visits  ref idx_month_visited   idx_month_visited   21  const   1782148 Using where

「どこを使って」、マジ?

EDIT:申し訳ありませんが、month_visited列だけにINDEXを追加したことを指定するのを忘れていました:)(EXPLAINが示すように、実際には使用されません...)

これらの(明らかに)単純なクエリを改善するにはどうすればよいですか? 私は MySQL の初心者ですが、これらのクエリを実行するのに数分かかるのは普通ではないと思います。

ご意見ありがとうございます。

よろしくお願いします、

4

2 に答える 2

5

この回答でコメントを要約しています。

一般に、インデックスが使用されていないのは、それを使用してもあまり役に立たないためです。つまり、完全なテーブル スキャンと比較して多くの時間を節約することはできません (これは、インデックスのカーディナリティが低い場合に発生する傾向があります)。ここでは、選択する行とほぼ同じ数の行がテーブルにあるため、これが当てはまるようです。この場合、フル スキャンは通常、インデックスを使用するより安価です。

また、削除は「書き込み」アクションです。インデックスは読み取りを最適化しますが、書き込みのコストが高くなります (書き込み時にインデックスが再構築されるため)。したがって、いくつかの複雑なインデックスがあるという事実は役に立ちませんが、問題を悪化させます。インデックスは、取得する行数を絞り込むときに意味があります。そうしないと、実質的な利益が得られず、余分なオーバーヘッドが発生する可能性さえあります。また、最良の場合、インデックスは SELECT をより効率的にします。ただし、書き込み (挿入、更新、および削除) が高速になるわけではありません。それどころか、パフォーマンスが低下します。

したがって、絶対に必要ではないインデックスを削除するようにしてください。インデックスはトレードオフであり、書き込み操作 (挿入、更新、削除) を遅くする代償として、読み取り操作 (選択) を高速化する可能性があることに注意してください。これは、書き込み後にインデックスを再構築する必要があるためです。

これを試してみてください。dev.mysql.com/doc/refman/5.0/en/delete.html

さらに別のオプション (うまくいくかどうか、ここで大声で考えているだけです): visitss からいくつかの行を除いてすべてを削除したい場合は、行 "WHERE month != '2013-10' を補助テーブルに挿入できます。訪問を TRUNCATE し、補助テーブルから行を訪問に挿入し、最後に補助テーブルを TRUNCATE しますが、ご指摘のとおり、このプロセスの実行中は何らかのロックを設定する必要があります。

于 2013-11-01T12:57:59.610 に答える