問題
このテーブルがあるとしますtab
(フィドルが利用可能です)。
| g | a | b | v |
---------------------
| 1 | 3 | 5 | foo |
| 1 | 4 | 7 | bar |
| 1 | 2 | 9 | baz |
| 2 | 1 | 1 | dog |
| 2 | 5 | 2 | cat |
| 2 | 5 | 3 | horse |
| 2 | 3 | 8 | pig |
で行をグループ化してg
おり、グループごとに column から 1 つの値が必要ですv
。ただし、値は必要ありませんがa
、 maximal を含む行と、それらすべてからmaximal を含む行の値が必要ですb
。言い換えれば、私の結果は
| 1 | bar |
| 2 | horse |
現在のソリューション
これを達成するためのクエリを知っています:
SELECT grps.g,
(SELECT v FROM tab
WHERE g = grps.g
ORDER BY a DESC, b DESC
LIMIT 1) AS r
FROM (SELECT DISTINCT g FROM tab) grps
質問
しかし、私はこのクエリはかなり醜いと考えています。主に依存サブクエリを使用しているため、実際のパフォーマンスキラーのように感じます. したがって、この問題に対するより簡単な解決策があるかどうか疑問に思っています。
予想される答え
この質問に対する最も可能性の高い答えは、このための機能を提供する MySQL (または MariaDB) のアドオンまたはパッチのようなものです。しかし、他の有用なインスピレーションも歓迎します。依存サブクエリなしで機能するものはすべて、回答として適格です。
cat
あなたの解決策が単一の順序付け列でのみ機能する場合、つまりとを区別できなかった場合はhorse
、その回答を自由に提案してください。大多数のユース ケースでも役立つと思います。たとえば100*a+b
、単一の式のみを使用しながら、両方の列で上記のデータを並べ替える可能性が高い方法です。
私はかなりハックな解決策をいくつか考えていて、しばらくしたら追加するかもしれませんが、最初にいくつかの素晴らしい新しい解決策が最初に流れ込むかどうかを確認します.
ベンチマーク結果
さまざまな回答を見て比較するのはかなり難しいため、いくつかのベンチマークを実行しました。これは、MySQL 5.1 を使用して、自分のデスクトップで実行しました。数値は他のシステムと比較することはできません。相互に比較するだけです。アプリケーションにとってパフォーマンスが重要な場合は、実際のデータを使用して独自のテストを行う必要があります。新しい回答が得られたら、それらをスクリプトに追加して、すべてのテストを再実行します。
- 100,000 項目、1,000 グループから選択可能、InnoDb:
- MvGで0.166秒(質問より)
- RichardTheKiwi の場合は0.520 秒
- xdazz で2.199 秒
- Dems の場合は 19.24 秒(順次サブクエリ)
- acatt の場合は48.72 秒
- 100,000 項目、50,000 グループから選択可能、InnoDb:
- xdazz の場合は0.356 秒
- RichardTheKiwi の場合は0.640 秒
- MvGで0.764秒(質問より)
- acatt の場合は51.50 秒
- Demsには長すぎます(順次サブクエリ)
- 100,000 項目、100 グループから選択可能、InnoDb:
- MvGで0.163秒(質問より)
- RichardTheKiwi の場合は0.523 秒
- Dems の場合は 2.072 秒(順次サブクエリ)
- xdazzの場合は17.78秒
- acatt の場合は49.85 秒
したがって、従属サブクエリを使用しても、これまでのところ私自身のソリューションはそれほど悪くはないようです。驚くべきことに、従属サブクエリも使用する acatt によるソリューションのパフォーマンスははるかに悪いものです。おそらく、MySQL オプティマイザが対処できないものです。RichardTheKiwi が提案したソリューションは、全体的なパフォーマンスも優れているようです。他の 2 つのソリューションは、データの構造に大きく依存します。多くのグループと小さなグループでは、xdazz のアプローチは他のすべてのアプローチよりも優れていますが、Dems によるソリューションは少数の大規模なグループでは最高のパフォーマンスを発揮します (それでも例外的に良くはありません)。