.. ============================ Database access optimization ============================ ============================ データベースアクセスの最適化 ============================ .. Django's database layer provides various ways to help developers get the most out of their databases. This document gathers together links to the relevant documentation, and adds various tips, organized under a number of headings that outline the steps to take when attempting to optimize your database usage. Django のデータベース層は、開発者がデータベースから多くを得ることを助ける色々 な方法を提供しています。このドキュメントは関連するドキュメントのリンクを集めて 色々なヒントを加え、データベース利用の最適化を試みる時に踏むべきステップを概略 する多くの見出しのもとに整理しています。 .. Profile first ============= まずは計測 ========== .. As general programming practice, this goes without saying. Find out :ref:`what queries you are doing and what they are costing you `. You may also want to use an external project like django-debug-toolbar_, or a tool that monitors your database directly. 一般的なプログラミングの実践として、これは言うまでもないことです。 :ref:`実行されるクエリと実行にかかるコスト` を見てく ださい。また、 django-debug-toolbar_ のような外部のプロジェクトや、データベー スを直接モニタするツールを使っても良いでしょう。 .. Remember that you may be optimizing for speed or memory or both, depending on your requirements. Sometimes optimizing for one will be detrimental to the other, but sometimes they will help each other. Also, work that is done by the database process might not have the same cost (to you) as the same amount of work done in your Python process. It is up to you to decide what your priorities are, where the balance must lie, and profile all of these as required since this will depend on your application and server. 必要に従って、速度を最適化するのか、メモリを最適化するのか、または両方なのかを 思い出してください。時には一方の最適化が他方にとって有害なものになりますが、ま た時には互いに助けになります。また、データベースプロセスでの処理は、 Python プ ロセスで行われる同じ量の処理と同じコストにならないかもしれません。優先度がどう か、バランスを取るべきか、全ての計測が必要か、を決定するのはあなたです。これら はアプリケーションとサーバに依存するでしょうから。 .. With everything that follows, remember to profile after every change to ensure that the change is a benefit, and a big enough benefit given the decrease in readability of your code. **All** of the suggestions below come with the caveat that in your circumstances the general principle might not apply, or might even be reversed. 以下の全てにおいて、変更が利益を生んでいることを確かめるため、そして大きすぎる 利益がコードの可読性を下げていないかを確かめるため、変更を行うごとに計測するの を忘れないようにしてください。以下の示唆 ** 全て ** について言えることですが、 あなたの環境では一般的な原則が当てはまらないかもしれない、もしかすると逆かもし れないということに注意してください。 .. _django-debug-toolbar: https://github.com/django-debug-toolbar/django-debug-toolbar/ .. Use standard DB optimization techniques ======================================= 標準的な DB 最適化テクニックを使う ================================== .. ...including: 以下が含まれます: .. * Indexes. This is a number one priority, *after* you have determined from profiling what indexes should be added. Use :attr:`django.db.models.Field.db_index` to add these from Django. * インデックス。計測の結果インデックスを追加するべきだと決心した *後には* これ を最も優先すべきです。インデックスを追加するには :attr:`django.db.models.Field.db_index` を使います。 .. * Appropriate use of field types. * 適切なフィールドの型を使います。 .. We will assume you have done the obvious things above. The rest of this document focuses on how to use Django in such a way that you are not doing unnecessary work. This document also does not address other optimization techniques that apply to all expensive operations, such as :doc:`general purpose caching `. 上記の明らかなことは既に行ってあると仮定します。このドキュメントの残りでは、必 要のないことをしないためにどのように Django を使うかに焦点を当てます。このド キュメントはまた、 :doc:`汎用的なキャッシング ` のような高くつ く操作全般に適用するような最適化技術は扱いません。 .. Understand QuerySets ==================== クエリセットを理解する ====================== .. Understanding :doc:`QuerySets ` is vital to getting good performance with simple code. In particular: :doc:`クエリセット ` を理解することはシンプルなコードで 良いパフォーマンスを得るために欠かせません。とりわけ: .. Understand QuerySet evaluation ------------------------------ クエリセットの評価を理解する ---------------------------- .. To avoid performance problems, it is important to understand: パフォーマンスの問題を避けるには、次のことを理解することが大切です: .. * that :ref:`QuerySets are lazy `. * :ref:`クエリセットが遅延評価 ` であること。 .. * when :ref:`they are evaluated `. * いつ :ref:`クエリセットが評価されるか ` 。 .. * how :ref:`the data is held in memory `. * :ref:`データがメモリに保持される ` 方法。 .. Understand cached attributes ---------------------------- キャッシュされる属性を理解する ------------------------------ .. As well as caching of the whole ``QuerySet``, there is caching of the result of attributes on ORM objects. In general, attributes that are not callable will be cached. For example, assuming the :ref:`example Weblog models `:: .. >>> entry = Entry.objects.get(id=1) >>> entry.blog # Blog object is retrieved at this point >>> entry.blog # cached version, no DB access ``QuerySet`` 全体をキャッシュするのと同様、 ORM オブジェクトの属性の結果も キャッシュされます。一般的に呼び出し可能でない属性はキャッシュされます。例えば :ref:`ブログでのモデル例 ` を前提にすると:: >>> entry = Entry.objects.get(id=1) >>> entry.blog # Blog オブジェクトはこの時点で検索されます >>> entry.blog # キャッシュバージョンが使われ、 DB アクセスしません .. But in general, callable attributes cause DB lookups every time:: .. >>> entry = Entry.objects.get(id=1) >>> entry.authors.all() # query performed >>> entry.authors.all() # query performed again しかし一般的に、呼び出し可能な属性は毎回 DB 参照を行います:: >>> entry = Entry.objects.get(id=1) >>> entry.authors.all() # クエリが実行された >>> entry.authors.all() # クエリがまた実行された .. Be careful when reading template code - the template system does not allow use of parentheses, but will call callables automatically, hiding the above distinction. テンプレートコードを読む時には注意してください。テンプレートシステムはカッコを 使うことを許容しませんが、上記の区別なく呼び出し可能オブジェクトを自動的に呼び ます。 .. Be careful with your own custom properties - it is up to you to implement caching. 自分のカスタムプロパティに注意してください。キャッシュを実装するかは開発者に任 されています。 .. Use the ``with`` template tag ----------------------------- ``with`` テンプレートタグを使う ------------------------------- .. To make use of the caching behavior of ``QuerySet``, you may need to use the :ttag:`with` template tag. ``QuerySet`` のキャッシング動作を利用するには、 :ttag:`with` テンプレートタグ を使う必要があるかもしれません。 .. Use ``iterator()`` ------------------ ``iterator()`` を使う --------------------- .. When you have a lot of objects, the caching behavior of the ``QuerySet`` can cause a large amount of memory to be used. In this case, :meth:`~django.db.models.query.QuerySet.iterator()` may help. 多くのオブジェクトを持っている時、 ``QuerySet`` のキャッシング動作は大量のメモ リ使用につながる可能性があります。この場合、 :meth:`~django.db.models.query.QuerySet.iterator()` が助けになるかもしれませ ん。 .. Do database work in the database rather than in Python ====================================================== Python よりもデータベースで行うべき動作 ======================================= .. For instance: 具体例として: .. * At the most basic level, use :ref:`filter and exclude ` to do filtering in the database. * 最も基本的なレベルでは、 :ref:`filter と exclude ` を使って データベースのフィルタリングをすることができます。 .. * Use :ref:`F() object query expressions ` to do filtering against other fields within the same model. * :ref:`F() オブジェクトクエリ表現 ` を使って同じモデルの中 で他のフィールドに対するフィルタリングを行えます。 .. * Use :doc:`annotate to do aggregation in the database `. * :doc:`データベースの集約のために注釈 ` を使います。 .. If these aren't enough to generate the SQL you need: 必要なSQLを生成するのにこれらで不十分なら: .. Use ``QuerySet.extra()`` ------------------------ ``QuerySet.extra()`` を使う --------------------------- .. A less portable but more powerful method is :meth:`~django.db.models.query.QuerySet.extra()`, which allows some SQL to be explicitly added to the query. If that still isn't powerful enough: 移植性は比較的低いですが、より強力なメソッドが :meth:`~django.db.models.query.QuerySet.extra()` です。これはクエリに対する明 示的な SQL の追加を可能にします。これでもまだ十分強力じゃないなら: .. Use raw SQL ----------- 生の SQL を使う --------------- .. Write your own :doc:`custom SQL to retrieve data or populate models `. Use ``django.db.connection.queries`` to find out what Django is writing for you and start from there. :doc:`データを検索したりモデルを作成するためのカスタム SQL ` を自分で書いてください。 ``django.db.connection.queries`` を使うと、 Django が 書き出したクエリを見ることができますので、そこから始めましょう。 .. Retrieve everything at once if you know you will need it ======================================================== 必要になると分かっているデータを一度に検索する ============================================== .. Hitting the database multiple times for different parts of a single 'set' of data that you will need all parts of is, in general, less efficient than retrieving it all in one query. This is particularly important if you have a query that is executed in a loop, and could therefore end up doing many database queries, when only one was needed. So: 一般的に、一つのデータ「集合」の別々の部分のために、データベースを複数回叩くの は、一つのクエリで一度に検索するよりも効率が低いです。 もしクエリがループの中で実行されていて、それ故に多くのデータベースクエリを一つ だけにまとめることが必要なら、特に重要です。 .. Use ``QuerySet.select_related()`` and ``prefetch_related()`` ------------------------------------------------------------ ``QuerySet.select_related()`` と ``prefetch_related()`` を使う -------------------------------------------------------------- .. Understand :meth:`~django.db.models.query.QuerySet.select_related` and :meth:`~django.db.models.query.QuerySet.prefetch_related` thoroughly, and use them: :meth:`~django.db.models.query.QuerySet.select_related` と :meth:`~django.db.models.query.QuerySet.prefetch_related` を完全に理解して使っ てください: .. * in view code, * ビューコードで。 .. * and in :doc:`managers and default managers ` where appropriate. Be aware when your manager is and is not used; sometimes this is tricky so don't make assumptions. * 適切な :doc:`マネジャとデフォルトマネジャ ` で。 いつマネジャが使われて、いつ使われないかに気をつけてください。時にこれはトリ ッキーで、予測しづらいものです。 .. Don't retrieve things you don't need ==================================== 必要ないものを検索しない ======================== .. Use ``QuerySet.values()`` and ``values_list()`` ----------------------------------------------- ``QuerySet.values()`` と ``values_list()`` を使う ------------------------------------------------- .. When you just want a ``dict`` or ``list`` of values, and don't need ORM model objects, make appropriate usage of :meth:`~django.db.models.query.QuerySet.values()`. These can be useful for replacing model objects in template code - as long as the dicts you supply have the same attributes as those used in the template, you are fine. 値の ``dict`` か ``list`` が必要なだけで、 ORM モデルオブジェクトが必要ないな ら、 :meth:`~django.db.models.query.QuerySet.values()` を適切に使ってください。 これらはテンプレートコードのモデルオブジェクトを置き換えるのに便利です。辞書が テンプレートで使われているものと同じ属性を持っているなら、うまく行きます。 .. Use ``QuerySet.defer()`` and ``only()`` --------------------------------------- ``QuerySet.defer()`` と ``only()`` を使う ----------------------------------------- .. Use :meth:`~django.db.models.query.QuerySet.defer()` and :meth:`~django.db.models.query.QuerySet.only()` if there are database columns you know that you won't need (or won't need in most cases) to avoid loading them. Note that if you *do* use them, the ORM will have to go and get them in a separate query, making this a pessimization if you use it inappropriately. 必要のない (またはほとんどの場合に必要ない) データベースカラムがあると分かって いるなら、それらをロードしないように :meth:`~django.db.models.query.QuerySet.defer()` と :meth:`~django.db.models.query.QuerySet.only()` を使ってください。 もしそのようなカラムを *使う* 場合は、 ORM が個別のクエリで取りに行かなければ ならないことに注意してください。不適切にそれを使うなら、悲観的に考えましょう。 .. Also, be aware that there is some (small extra) overhead incurred inside Django when constructing a model with deferred fields. Don't be too aggressive in deferring fields without profiling as the database has to read most of the non-text, non-VARCHAR data from the disk for a single row in the results, even if it ends up only using a few columns. The ``defer()`` and ``only()`` methods are most useful when you can avoid loading a lot of text data or for fields that might take a lot of processing to convert back to Python. As always, profile first, then optimize. また、遅延フィールドを使ってモデルを構築する時に Django の中でいくらかの (小さ な追加の) オーバーヘッドが発生することに注意してください。計測なしでの遅延 フィールドの使用に積極的になりすぎないでください。わずかなカラムしか使っていな い時でも、データベースは結果の 1 つの行のためにほとんどの非 text 型、非 VARCHAR 型のデータをディスクから読み出さなければなりません。 ``defer()`` と ``only()`` メソッドは多くのテキストデータや Python データに戻すために多くの処 理が必要となるフィールドのロードを避けるのにはとても便利です。例によって、まず は計測、それから最適化をしましょう。 .. Use QuerySet.count() -------------------- QuerySet.count() を使う ----------------------- .. ...if you only want the count, rather than doing ``len(queryset)``. 数を数えたいだけなら、 ``len(queryset)`` を使うよりもこちらの方が良いです。 .. Use QuerySet.exists() --------------------- QuerySet.exists() を使う ------------------------ .. ...if you only want to find out if at least one result exists, rather than ``if queryset``. 少なくとも 1 つの結果が存在するかを調べたいだけなら、 ``if queryset`` よりもこ ちらの方が良いです。 .. But: しかし: .. Don't overuse ``count()`` and ``exists()`` ------------------------------------------ ``count()`` と ``exists()`` を使いすぎない ------------------------------------------ .. If you are going to need other data from the QuerySet, just evaluate it. QuerySet からの他のデータが必要なら、それを評価しましょう。 .. For example, assuming an Email model that has a ``body`` attribute and a many-to-many relation to User, the following template code is optimal: 例えば、 ``body`` 属性とユーザへの多対多のリレーションを持っている電子メールモ デルを考えましょう。以下のテンプレートコードは最適です: .. code-block:: html+django {% if display_inbox %} {% with emails=user.emails.all %} {% if emails %}

You have {{ emails|length }} email(s)

{% for email in emails %}

{{ email.body }}

{% endfor %} {% else %}

No messages today.

{% endif %} {% endwith %} {% endif %} .. It is optimal because: これが最適な理由は: .. 1. Since QuerySets are lazy, this does no database queries if 'display_inbox' is False. 1. QuerySets が遅延評価されるので display_inbox が False の場合にデータベース アクセスが発生しません。 .. #. Use of :ttag:`with` means that we store ``user.emails.all`` in a variable for later use, allowing its cache to be re-used. #. :ttag:`with` を使うと、あとで使われるために ``user.email_all`` を変数に保存 します。再利用できるキャッシュが使われます。 .. #. The line ``{% if emails %}`` causes ``QuerySet.__nonzero__()`` to be called, which causes the ``user.emails.all()`` query to be run on the database, and at the least the first line to be turned into an ORM object. If there aren't any results, it will return False, otherwise True. #. ``{% if emails %}`` 行は ``QuerySet.__nonzero__()`` の呼び出しを引き起こし ます。これは ``user.emails.all()`` がデータベースで実行されることにつながり ます。少なくとも一行目が ORM オブジェクトに変換されます。結果がなければ False を返し、あれば True を返します。 .. #. The use of ``{{ emails|length }}`` calls ``QuerySet.__len__()``, filling out the rest of the cache without doing another query. #. ``{{ emails|length }}`` は ``QuerySet.__len__()`` を呼びます。他のクエリを 実行せずにキャッシュの残りを満たします。 .. #. The :ttag:`for` loop iterates over the already filled cache. #. :ttag:`for` ループは既に満たされているキャッシュの上に繰り返されます。 .. In total, this code does either one or zero database queries. The only deliberate optimization performed is the use of the :ttag:`with` tag. Using ``QuerySet.exists()`` or ``QuerySet.count()`` at any point would cause additional queries. 全体として、このコードは 1 個か 0 個のデータベースクエリを実行します。 唯一の計画的な最適化の実施が :ttag:`with` タグ の使用です。どの箇所で ``QuerySet.exists()`` や ``QuerySet.count()`` を使っても追加のクエリの原因にな ります。 .. Use ``QuerySet.update()`` and ``delete()`` ------------------------------------------ ``QuerySet.update()`` と ``delete()`` を使う -------------------------------------------- .. Rather than retrieve a load of objects, set some values, and save them individual, use a bulk SQL UPDATE statement, via :ref:`QuerySet.update() `. Similarly, do :ref:`bulk deletes ` where possible. オブジェクトを検索してロードし、何かの値をセットして個別に保存するよりも、 :ref:`QuerySet.update()` 経由でバルクの SQL UPDATE 文を使うほうが良いです。同 様に、可能な限り :ref:`バルクでの削除 ` を使いましょ う。 .. Note, however, that these bulk update methods cannot call the ``save()`` or ``delete()`` methods of individual instances, which means that any custom behavior you have added for these methods will not be executed, including anything driven from the normal database object :doc:`signals `. しかしながら、これらのバルクアップデートメソッドは個別のインスタンスの ``save()`` や ``delete()`` メソッドを呼べないことに注意してください。つまり、 通常のデータベースオブジェクト :doc:`シグナル ` によって起動され るものも含め、開発者がこれらのメソッドに追加したいかなるカスタムの動作も実行さ れないことになります。 .. Use foreign key values directly ------------------------------- 外部キーの値を直接使う ---------------------- .. If you only need a foreign key value, use the foreign key value that is already on the object you've got, rather than getting the whole related object and taking its primary key. i.e. do:: 外部キーの値が必要なだけなら、関連するオブジェクトの全体を取得してそのプライマ リキーを得るのではなく、既に取得しているオブジェクトの外部キーの値を使いましょ う。例えばこのようにする代わりに:: entry.blog.id .. instead of:: こうします:: entry.blog_id .. Insert in bulk ============== バルクでのインサート ==================== .. When creating objects, where possible, use the :meth:`~django.db.models.query.QuerySet.bulk_create()` method to reduce the number of SQL queries. For example:: 複数のオブジェクトを作る時、可能であれば、 :meth:`~django.db.models.query.QuerySet.bulk_create()` メソッドを使って SQL ク エリの数を減らしましょう。例えば:: Entry.objects.bulk_create([ Entry(headline="Python 3.0 Released"), Entry(headline="Python 3.1 Planned") ]) .. ...is preferable to:: が以下よりも望ましいです:: Entry.objects.create(headline="Python 3.0 Released") Entry.objects.create(headline="Python 3.1 Planned") .. Note that there are a number of :meth:`caveats to this method `, so make sure it's appropriate for your use case. :meth:`このメソッドに関する注意 ` がたくさんありますので、ユースケースに合致しているか確認してください。 .. This also applies to :class:`ManyToManyFields `, so doing:: このことは :class:`ManyToManyFields ` にも当 てはまります。このようにすることは:: my_band.members.add(me, my_friend) .. ...is preferable to:: 以下よりも良いです:: my_band.members.add(me) my_band.members.add(my_friend) .. ...where ``Bands`` and ``Artists`` have a many-to-many relationship. ここで ``Bands`` と ``Artists`` は多対多の関係を持っているとします。