最新のスプリントタイムで注文されたランナーのリストを表示したいと考えます。Django:最新の子モデルフィールドに基づいてクエリセットを注文する
class Runner(models.Model):
name = models.CharField(max_length=255)
class Sprint(models.Model):
runner = models.ForeignKey(Runner)
time = models.PositiveIntegerField()
created = models.DateTimeField(auto_now_add=True)
これは私がSQLにどうなるのかの簡単なスケッチです:
SELECT runner.id, runner.name, sprint.time
FROM runner
LEFT JOIN sprint ON (sprint.runner_id = runner.id)
WHERE
sprint.id = (
SELECT sprint_inner.id
FROM sprint as sprint_inner
WHERE sprint_inner.runner_id = runner.id
ORDER BY sprint_inner.created DESC
LIMIT 1
)
OR sprint.id = NULL
ORDER BY sprint.time ASC
Django QuerySet documentation状態:
注文する複数値フィールドを指定することが許されています結果は (たとえば、ManyToManyFieldフィールド)。通常、これは実行するには 分かりやすいものではなく、実際は高度な使用方法です。 しかし、クエリセットのフィルタリングまたは利用可能なデータ が、 のそれぞれのデータの注文データを1つだけ選択することを意味する場合、注文は正確に となります。注意して多値フィールドでの注文を使用し、 の結果が期待どおりであることを確認してください。
私はここにいくつかのフィルタを適用する必要があると思いますが、私はそれがこの例では明らかにされていませんので、Djangoは...
つのノートを見込んで正確に何かわからない:ランナーテーブルには、いくつかを持っています百回のエントリーでは、スプリントには数百もあり、後にはおそらく数千ものエントリーがあります。データは改ページされたビューで表示されるので、Pythonでのソートはオプションではありません。
唯一の他の可能性は、自分自身でSQLを書くことですが、私はこれを避けたいと思います。私は一つだけのクエリでORMを経由してこれを行う方法はないと思う
これは比較的高いメモリ使用量を引き起こしませんか?私が見ることができる限り、少なくともすべてのランナーをメモリに引き込み、かなり大きなスプリントIDのリストを作成します。これをDBに数百人のランナーがいるすべてのページビューで実行すると、私は少し*不快な気分になります。これがキャッシングが始まる場所です。 – Strayer
これを10,000人のランナーでテストした結果、10MB(実際には3MB)未満のRAMが使用されました。それ以上のものを必要としていると思われる場合は、実際には未処理のSQLを使用する必要があります。いつものように、これに対する最善のアプローチは、最初にプロファイルすることです - 推測ではありません。早期の最適化とそのすべて... – Matt
そして、数百のレコードは実際にはあまり多くはありません...パフォーマンスの最適化について心配することはありません。通常数十万件のレコードが考えられますが、それでも通常は問題はあまりありません(インデックスを1つか2つにして解決します)。 – Matt