顧客テーブルと購入テーブルがあるとします。各購入は 1 人の顧客に属します。1 つのSELECT
ステートメントですべての顧客のリストと最後の購入を取得したいと考えています。ベスト プラクティスは何ですか? インデックスの作成に関するアドバイスはありますか?
回答には次の表/列名を使用してください。
- お客様:
id
、name
- 購入:
id
、customer_id
、item_id
、date
さらに複雑な状況では、最後の購入を顧客テーブルに入れてデータベースを非正規化すると (パフォーマンスの面で) 有利になりますか?
(購入) がid
日付順にソートされることが保証されている場合、次のようなものを使用してステートメントを簡略化できますかLIMIT 1
?
ベストアンサー1
greatest-n-per-group
これは、StackOverflow で定期的に発生する問題の例です。
通常、私は次のように解決することをお勧めします。
SELECT c.*, p1.*
FROM customer c
JOIN purchase p1 ON (c.id = p1.customer_id)
LEFT OUTER JOIN purchase p2 ON (c.id = p2.customer_id AND
(p1.date < p2.date OR (p1.date = p2.date AND p1.id < p2.id)))
WHERE p2.id IS NULL;
説明: 行 が与えられた場合、同じ顧客で日付が後の行 (同点の場合は後の)p1
は存在しないはずです。これが真であると判明した場合、 はその顧客の最新の購入になります。p2
id
p1
purchase
インデックスに関しては、列 ( customer_id
、、 )に複合インデックスを作成します。これにより、カバーリング インデックスdate
をid
使用して外部結合を実行できるようになります。最適化は実装に依存するため、必ずプラットフォームでテストしてください。RDBMS の機能を使用して、最適化プランを分析します。たとえば、EXPLAIN
MySQL の場合です。
上記で示した解決策の代わりにサブクエリを使用する人もいますが、私の解決策の方が同点の解決が容易になると思います。