100万レコード程(1つのレコードは1~最大100文字、平均10文字程度のローマ字または日本語でフィールド数は15)のDBがあります。
主キーはindexというフィールド名で、auto_incrementで単純に1から番号が増えていき、1~1000000まであります。
さて、フィールドのうちの一つ id を指定して、その最後のレコードを取り出したいのですが、クエリとして
select * from test where id = 'id5' order by index desc limit 1
を使っています(1分に数回程度実行)が、この処理が重いらしく、度々DBが落ち、ログインできなくなります。
サポートに連絡すると、「未処理のクエリが残っていたので強制終了しました」とあり、その後ログインできるようになります。
これを解消したいです。
そこで質問があり、内容をコメント欄に示しました。
どうかお力添えをよろしくお願いします。
1)取出すフィールドの数を減らす?
今回は取出すレコードが1件だけなので、
根本的なものではなく、とりあえずはそのままで良い
2)カラムを空にする?
今件のままの環境およびSQLであれば、
多少なりとも軽量化に寄与する可能性はあるけれど、
根本的なものではないため、とりあえずはそのままで良い
4)昔のレコードを削除する?
今件のままの環境およびSQLであれば、
大量のレコード削除は劇的な速度アップに寄与するため、
必要な措置ではあるけれど、根本的な解決ではない
3)クエリだけでの解決方法は?
無理
原因はフルスキャンによるタイムオーバー&暴走と思われるので、
まずはインデックス用フィールドを作ってみることを勧めてみたい
フィールド名に予約語を含むことの是非は置いておくとして、
index2 というフィールドを追加して下記のように計算した値を入れる
index2 = 10,000,000 - index
次に
id, index2 でインデックスを作成
問い合わせは下記のいずれかとする
SELECT * FROM test WHERE id = 'id5' ORDER BY index2 LIMIT 1
SELECT * FROM test WHERE id = 'id5' ORDER BY id, index2 LIMIT 1
根本部分から説明するとどれだけになるかわからないので、ひとまず以上です
(無料質問でどこまで回答すべき/せざるべきかか悩み中・・・)
「ポイントをくれ」と言っている訳ではありません
2011/11/22 15:33:00(有料質問だけでなく無料質問にもかなりの割合で多数回答しています)
無料でもどこまでも回答してくれるというイメージがついてしまうと、
「ポイント配分しないと回答しない人」がますます締め出され、
回答者不足がさらに加速するということを懸念してのことです
さて、話を戻しまして、
まずはMySQLのデータベースエンジンの欠点を知っておくべきでしょう
・1つのクエリでは1つのインデックスしか利用できない
・どのインデックスを利用するかについての選択がイマイチ
・降順すなわちDESCについてはフルスキャンとなってしまう
もっとも足を引っ張るフルスキャン対策として、
index2(以後uniquekey2にしますね)を用意して昇順としています
(マイナス値は先頭ビットで判断するので多分ダメなように思いますが、
マイナス値を用いての処理速度についてテストはしたことありません)
そして適切なインデックスを選択させるための努力として
idもORDER BYに入れてみることも提案しています
SELECT 中略 ORDER BY id, uniquekey2 LIMIT 1
なお、
EXPLAINの使い方はSQLの先頭にEXPLAINという言葉を付けるだけですが、
EXPLAINの結果を受け取るようにはなっていないプログラム中に書いてもダメです
phpMyAdminなどのツールから実施するか、あるいは、
別途phpなどでEXPLAINを実行するためだけのテストプログラムを作って実験することとなります
>「ポイントをくれ」と言っている訳ではありません
2011/11/22 16:00:22理解しました。
>index2(以後uniquekey2にしますね)を用意して昇順としています
負の値になるのを避けるため、100万ではなく、1000万から引いた値を使ってみたいと思います。
>SELECT 中略 ORDER BY id, uniquekey2 LIMIT 1
それも試してみたいと思います。
select * from test where id = 'id5' order by id, uniquekey limit 1
ということですね。