初めまして、最近SQLをかじり始めたぺーぺーです。
効率の悪いSELECT文しか書けずに困っています。
下記のテーブルsoftware_tableから、
・name列「oracle」
・version値が最大
のレコードに含まれるid(=3)を拾ってきたいのですが、自分の頭では副問い合わせを使う方法か、ソートを使う方法しか思いつきません。
問題は副問い合わせ・ソートを使うと計算コストが大きくなってしまうことで、できることなら副問い合わせ・ソートを使わずに解決したいのですが、何か方法はないものでしょうか?
よろしくお願い致します。
-----------------------------
software_table
id name version
1 oracle 1
2 oracle 2
3 oracle 3
4 postgres 1
5 postgres 2
6 postgres 3
7 postgres 4
-----------------------------
■副問い合わせを使った方法
SELECT id FROM software_table
WHERE
name = 'oracle' AND
version = (SELECT max(version) FROM software_table WHERE name = 'oracle');
■ソートを使った例
SELECT id FROM software_table
WHERE name = 'oracle' ORDER BY version DESC LIMIT 1 OFFSET 0;
-----------------------------
基本的には副問い合わせやソートはコストのかかる処理です。
ただ, それはデータ件数が数十万, 数百万にもなった場合に実際に体感できる負荷として顕在化してきます。
software_table に格納されるデータ量の見積もりはどのくらいを想定しているのでしょうか?
格納されて高々数千件というレベルであれば, 書かれてある副問い合わせやソートを使っても全く問題ないと思います。
また, name属性で検索結果がかなり絞り込めるのであれば,
その後に MAX関数で最大値を求めようがソートで並び替えをしようがコストはほとんどかかりません。
副問い合わせやソートは必ずしも悪というわけではなく, 状況によって使い分ければよいと思います。
ちなみに GROUP BY を使って以下のようにもかけます。
が, 特に効率がいいということはありません ^^;
SELECT name, MAX(version) FROM software_table
WHERE name = 'oracle' GROUP BY name;
お礼
なるほどと思いました。で、nameとversionの最大値の組み合わせでの参照は頻繁に行われるため、試しに参照用のテーブルを作成して実行計画を見てみました。 のですが、、速度を計測してみたところレスポンスは副問い合わせを使ったときの方が早いようです(レコード3万件で実験)。 おそらくテーブルの結合に時間がかかってしまってることが原因ではないかと考えています。 しかし今回はたまたまテーブル結合が無いケースでしたが、もともとのSELECT文でテーブル結合をする必要がある場合には、参照用のテーブルを作ったほうが早いかもしれませんね。 何度もアドバイスをくださってありがとうございます。もはや改善は無理っぽい感じですが、重要な部分なのでもう一日だけ頑張ってみようと思います^^;