10

Valorというモデルを持っています。バロールにはロボットがいます。私はこのように問い合わせています:

Valor.objects.filter(robot=r).reverse()[0]

r ロボットの最後のバロールを取得します。Valor.objects.filter(robot=r).count() は約 200000 で、私の PC では最後のアイテムを取得するのに約 4 秒かかります。

どうすれば高速化できますか?間違った方法でクエリを実行していますか?

4

9 に答える 9

8

この問題に対する最適な mysql 構文は、次のようなものです。

SELECT * FROM table WHERE x=y ORDER BY z DESC LIMIT 1

これに相当する django は次のようになります。

Valor.objects.filter(robot=r).order_by('-id')[:1][0]

このソリューションが、オブジェクトのリストをコンパイルする前に、 django のスライシングメソッドを使用してクエリセットを制限する方法に注意してください。

于 2011-11-30T15:15:26.330 に答える
4

データセットが十分に大きくなり、物事を少し非正規化したくなるようです。Robot オブジェクトの最後の Valor オブジェクトを追跡しようとしましたか?

class Robot(models.Model):
    # ...
    last_valor = models.ForeignKey('Valor', null=True, blank=True)

そして、post_save シグナルを使用して更新を行います。

from django.db.models.signals import post_save

def record_last_valor(sender, **kwargs):
    if kwargs.get('created', False):
        instance = kwargs.get('instance')
        instance.robot.last_valor = instance

post_save.connect(record_last_valor, sender=Valor)

Valor オブジェクトを作成するときに追加の db トランザクションのコストを支払うことになりますが、last_valor ルックアップは非常に高速です。それを試して、トレードオフがアプリにとって価値があるかどうかを確認してください。

于 2009-12-05T18:01:10.723 に答える
3

django 1.6 では .first() と .last() が導入されました。

https://docs.djangoproject.com/en/1.6/ref/models/querysets/#last

したがって、次のように簡単に実行できます。

Valor.objects.filter(robot=r).last()
于 2014-07-16T12:00:43.853 に答える
3

まあ、order_by句がないので、「最後」とはどういう意味なのか気になります。「最後に追加された」という意味であると仮定すると、

Valor.objects.filter(robot=r).order_by('-id')[0]

あなたのために仕事をするかもしれません。

于 2009-12-05T17:08:29.763 に答える
1

また、非常に高速である必要があります。

qs = Valor.objects.filter(robot=r) # <-- it doesn't hit the database
count = qs.count()                 # <-- first hit the database, compute a count
last_item = qs[ count-1 ]          # <-- second hit the database, get specified rownum

したがって、実際には 2 つの SQL クエリのみを実行します ;)

于 2012-05-19T08:58:59.660 に答える
0
Model_Name.objects.first()

//最初の要素を取得する場合

Model_name.objects.last()

// get last() の場合

私の場合、データベースには行が1つしかないため、最後は機能しません:)

于 2015-02-09T15:00:37.900 に答える
0

djangoに制限句はありますか? このようにして、データベースを取得し、単一のレコードを返すことができます。

mysql

 select * from table where x = y limit 1

SQLサーバー

 select top 1 * from table where x = y

オラクル

 select * from table where x = y and rownum = 1

これが django に翻訳されていないことはわかっていますが、誰かが戻ってきてこれをクリーンアップできます。

于 2009-12-05T17:13:13.267 に答える
0

これを行う正しい方法は、組み込みの QuerySet メソッド latest() を使用して、ソートする列 (フィールド名) をフィードすることです。欠点は、単一の db 列でしかソートできないことです。

現在の実装は次のようになり、@Aaron の提案と同じ意味で最適化されています。

def latest(self, field_name=None):
    """
    Returns the latest object, according to the model's 'get_latest_by'
    option or optional given field_name.
    """
    latest_by = field_name or self.model._meta.get_latest_by
    assert bool(latest_by), "latest() requires either a field_name parameter or 'get_latest_by' in the model"
    assert self.query.can_filter(), \
            "Cannot change a query once a slice has been taken."
    obj = self._clone()
    obj.query.set_limits(high=1)
    obj.query.clear_ordering()
    obj.query.add_ordering('-%s' % latest_by)
    return obj.get()
于 2014-03-12T21:56:19.747 に答える