---
title: "データベースアクセスの最適化"
version: 3.1
locale: ja
source: https://docs.djangoproject.com/ja/3.1/topics/db/optimization/
canonical: https://djangodocs.dev/ja/3.1/topics/db/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.

## Profile first

一般的なプログラミング手法と同様に、これは言うまでもないことです。[どんなクエリを実行し何がコストなのか](/ja/3.1/faq/models/#faq-see-raw-sql-queries) を判別してください。[`QuerySet.explain()`](/ja/3.1/ref/models/querysets/#django.db.models.query.QuerySet.explain) を使用し、データベース上で特定の `QuerySet` がどのように実行されるかを理解してください。また、[django-debug-toolbar](https://github.com/jazzband/django-debug-toolbar/) といった外部のプロジェクトや、データベースを直接監視するツールを使うのもいいでしょう。

要件に従って、速度またはメモリ、およびその両方を最適化することができます。片方を最適化することは、もう片方に悪影響を及ぼすことがありますが、互いに助けになることもあります。また、データベースプロセスによって行われる処理と Python のプロセスによる処理は (あなたにとって) 必ずしも同等のコストとはなりません。その優先順位とバランスを決めるのはあなた自身です。そして、その設計はアプリケーションやサーバーに依存するため、要求通りに設計するのもあなたの仕事です。

以下で紹介する項目すべてにおいて、あらゆる変更の後に忘れずに分析を行い、施した変更が有益だったこと、およびその恩恵が可読性の低下を十分上回ることを確認してください。以下の **すべて** の提案において、一般的な原則があなたの状況に当てはまらない可能性があること、それどころか逆効果になりかねない可能性さえあることに十分注意してください。

## 標準的な DB 最適化のテクニックを使う

以下のようなものが上げられます:

- [Indexes](https://en.wikipedia.org/wiki/Database_index). This is a number one priority, *after* you have determined from
  profiling what indexes should be added. Use
  [`Meta.indexes`](/ja/3.1/ref/models/options/#django.db.models.Options.indexes) or
  [`Field.db_index`](/ja/3.1/ref/models/fields/#django.db.models.Field.db_index) to add these from
  Django. Consider adding indexes to fields that you frequently query using
  [`filter()`](/ja/3.1/ref/models/querysets/#django.db.models.query.QuerySet.filter),
  [`exclude()`](/ja/3.1/ref/models/querysets/#django.db.models.query.QuerySet.exclude),
  [`order_by()`](/ja/3.1/ref/models/querysets/#django.db.models.query.QuerySet.order_by), etc. as indexes may help
  to speed up lookups. Note that determining the best indexes is a complex
  database-dependent topic that will depend on your particular application.
  The overhead of maintaining an index may outweigh any gains in query speed.

- フィールドタイプの適切な使用。

We will assume you have done the things listed 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 [general purpose caching](/ja/3.1/topics/cache/).

## `QuerySet` を理解する

[QuerySet](/ja/3.1/ref/models/querysets/) を理解することは、シンプルなコードでパフォーマンスを上げるために極めて重要です。特に:

### `QuerySet` の評価を理解する

パフォーマンスの問題を回避するには、以下を理解することが重要です:

- [QuerySet は lazy](/ja/3.1/topics/db/queries/#querysets-are-lazy) であること。
- いつ [QuerySet が評価されるのか](/ja/3.1/ref/models/querysets/#when-querysets-are-evaluated)。
- どのように [データがメモリ上に保持されるか](/ja/3.1/topics/db/queries/#caching-and-querysets)。

### キャッシュされる属性を理解する

`QuerySet` 全体をキャッシュすることに加えて、ORM オブジェクトの属性の結果のキャッシングも存在します。通常、呼び出し可能ではない属性はキャッシュされます。例として、 [Weblog モデルの例](/ja/3.1/topics/db/queries/#queryset-model-example)  を考えてみましょう:

```
>>> entry = Entry.objects.get(id=1)
>>> entry.blog   # Blog object is retrieved at this point
>>> entry.blog   # cached version, no DB access
```

その一方で、通常呼び出し可能な属性は毎回 DB の検索を引き起こします:

```
>>> entry = Entry.objects.get(id=1)
>>> entry.authors.all()   # query performed
>>> entry.authors.all()   # query performed again
```

テンプレート上のコードを読む際には注意が必要です - テンプレートシステムは括弧を許容していませんが、呼び出し可能なオブジェクトは自動的に呼び出されるので、上記の区別が隠れてしまいます。

独自のプロパティにも注意が必要です - 必要なときにキャッシングを実装するのはあなた次第です。たとえば [`cached_property`](/ja/3.1/ref/utils/#django.utils.functional.cached_property) デコレータを使用します。

### `with` テンプレートタグを使用する

`QuerySet` のキャッシング処理を活用するため、[`with`](/ja/3.1/ref/templates/builtins/#std-templatetag-with) テンプレートタグの使用が推奨されます。

### `iterator()` を使用する

多くのオブジェクトを扱う際には、`QuerySet` のキャッシング動作に多くのメモリが使われる可能性があります。この場合、[`iterator()`](/ja/3.1/ref/models/querysets/#django.db.models.query.QuerySet.iterator) が有用です。

### `explain()` を使用する

[`QuerySet.explain()`](/ja/3.1/ref/models/querysets/#django.db.models.query.QuerySet.explain) を使うと、使用されているインデックスや結合など、データベースがクエリをどのように実行しているのか、詳細な情報を得られます。この詳細情報は、より効率的になるようにクエリを書き換えたり、パフォーマンスを向上させるために追加できるインデックスを特定するのに役立ちます。

## データベースの仕事を Python ではなくデータベースに行わせる

例えば:

- 最も基本的なレベルでは、[filter や exclude](/ja/3.1/ref/models/querysets/#queryset-api) を使ってデータベース内でフィルタリングを行います。
- [`F expressions`](/ja/3.1/ref/models/expressions/#django.db.models.F) を使い、同一モデル内で他のフィールドに基づくフィルタリングを行います。
- [データベース内の集計をするためアノテーション](/ja/3.1/topics/db/aggregation/) を使います。

必要な SQL を生成するのに不十分な場合は:

### `RawSQL` を使用する

保守性は高くありませんが、より強力な方法は [`RawSQL`](/ja/3.1/ref/models/expressions/#django.db.models.expressions.RawSQL) 表現です。これにより、SQL を明示的にクエリに追加することができます。これでもまだ不十分な場合は:

### 素の SQL を使用する

[モデルの取り出しおよび書き込みをするための独自の SQL](/ja/3.1/topics/db/sql/) を記述します。`django.db.connection.queries` を使い、Django があなたのために何を書いているのかを理解して、それを元に始めてください。

## ユニークかつインデックス済みの列を使用して個別のオブジェクトを取得する

[`get()`](/ja/3.1/ref/models/querysets/#django.db.models.query.QuerySet.get) を使って個別オブジェクトを取得する際に、[`unique`](/ja/3.1/ref/models/fields/#django.db.models.Field.unique) や [`db_index`](/ja/3.1/ref/models/fields/#django.db.models.Field.db_index) が設定された列を使用するのには 2 つの理由があります。1 つは、データベースインデックスにより受け里が高速になるからです。加えて、複数のオブジェクトが検索にマッチするとクエリは遅くなります; 列にユニーク制限をかけることでこれを完全に防ぐことができます。

したがって、[Weblog モデルの例](/ja/3.1/topics/db/queries/#queryset-model-example) を使うと:

```
>>> entry = Entry.objects.get(id=10)
```

上記は以下よりも高速です:

```
>>> entry = Entry.objects.get(headline="News Item Title")
```

これは、`id` がデータベースによってインデックス化されていて、ユニークだと保証されているからです。

以下のようにすると非常に遅くなる恐れがあります:

```
>>> entry = Entry.objects.get(headline__startswith="News")
```

まず第一に、`headline` はインデックス化されておらず、データベースのデータ取り出しを遅くします。

そして第二に、この検索では単一のオブジェクトが返されることは保証されません。クエリが 1 つ以上のオブジェクトと一致する場合、すべてのオブジェクトをデータベースから取り出して転送します。この余分な負荷は、100 とか 1000 といった多量のレコードが返されるときには相当な量になります。データベースが複数のサーバーによって構成される場合、ネットワークのオーバーヘッドと待ち時間が発生するため、この負荷はさらに大きくなります。

## 必要なものが分かっているときは一度にすべてを取り出す

すべての部分を必要とする単一のデータセットの異なる部分に対してデータベースを何度もヒットするのは、一般的に、1 つのクエリですべてを取得するよりも非効率です。 これは、1 つのクエリだけが必要なときにループ内でクエリを実行し、その結果何度もデータベースクエリを実行することになってしまう場合に、特に重要となります。そこで:

### `QuerySet.select_related()` や `prefetch_related()` を使用する

[`select_related()`](/ja/3.1/ref/models/querysets/#django.db.models.query.QuerySet.select_related) と [`prefetch_related()`](/ja/3.1/ref/models/querysets/#django.db.models.query.QuerySet.prefetch_related) を徹底的に理解し、使用してください:

- 必要に応じて、[マネージャとデフォルトマネージャ](/ja/3.1/topics/db/managers/) の中で。マネージャが使用されているときと使用されていないときに注意してください; 誤りやすい部分なので、思い込みのないようにしてください。
- ビューのコードや他のレイヤーの中で。必要に応じて [`prefetch_related_objects()`](/ja/3.1/ref/models/querysets/#django.db.models.prefetch_related_objects) が利用できます。

## 必要ないものを取り出さない

### `QuerySet.values()` や `values_list()` を使用する

When you only want a `dict` or `list` of values, and don't need ORM model
objects, make appropriate usage of
[`values()`](/ja/3.1/ref/models/querysets/#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.

### `QuerySet.defer()` や `only()` を使用する

Use [`defer()`](/ja/3.1/ref/models/querysets/#django.db.models.query.QuerySet.defer) and
[`only()`](/ja/3.1/ref/models/querysets/#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.

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.

### Use `QuerySet.count()`

...if you only want the count, rather than doing `len(queryset)`.

### Use `QuerySet.exists()`

...if you only want to find out if at least one result exists, rather than `if
queryset`.

But:

### Don't overuse `count()` and `exists()`

If you are going to need other data from the QuerySet, evaluate it immediately.

たとえば、`body` 属性とUserモデルへの多対多リレーションをもつEmailモデルの場合、以下のテンプレートコードが最適です。

```html+django
{% if display_inbox %}
  {% with emails=user.emails.all %}
    {% if emails %}
      <p>You have {{ emails|length }} email(s)</p>
      {% for email in emails %}
        <p>{{ email.body }}</p>
      {% endfor %}
    {% else %}
      <p>No messages today.</p>
    {% endif %}
  {% endwith %}
{% endif %}
```

It is optimal because:

1. Since QuerySets are lazy, this does no database queries if 'display\_inbox'
   is False.
2. Use of [`with`](/ja/3.1/ref/templates/builtins/#std-templatetag-with) means that we store `user.emails.all` in a variable
   for later use, allowing its cache to be re-used.
3. The line `{% if emails %}` causes `QuerySet.__bool__()` 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.
4. The use of `{{ emails|length }}` calls `QuerySet.__len__()`, filling
   out the rest of the cache without doing another query.
5. The [`for`](/ja/3.1/ref/templates/builtins/#std-templatetag-for) loop iterates over the already filled cache.

In total, this code does either one or zero database queries. The only
deliberate optimization performed is the use of the [`with`](/ja/3.1/ref/templates/builtins/#std-templatetag-with) tag. Using
`QuerySet.exists()` or `QuerySet.count()` at any point would cause
additional queries.

### Use `QuerySet.update()` and `delete()`

Rather than retrieve a load of objects, set some values, and save them
individual, use a bulk SQL UPDATE statement, via [QuerySet.update()](/ja/3.1/topics/db/queries/#topics-db-queries-update). Similarly, do [bulk deletes](/ja/3.1/topics/db/queries/#topics-db-queries-delete) where possible.

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 [signals](/ja/3.1/ref/signals/).

### 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
```

### Don't order results if you don't care

Ordering is not free; each field to order by is an operation the database must
perform. If a model has a default ordering ([`Meta.ordering`](/ja/3.1/ref/models/options/#django.db.models.Options.ordering)) and you don't need it, remove
it on a `QuerySet` by calling
[`order_by()`](/ja/3.1/ref/models/querysets/#django.db.models.query.QuerySet.order_by) with no parameters.

Adding an index to your database may help to improve ordering performance.

## Use bulk methods

Use bulk methods to reduce the number of SQL statements.

### Create in bulk

When creating objects, where possible, use the
[`bulk_create()`](/ja/3.1/ref/models/querysets/#django.db.models.query.QuerySet.bulk_create) method to reduce the
number of SQL queries. For example:

```
Entry.objects.bulk_create([
    Entry(headline='This is a test'),
    Entry(headline='This is only a test'),
])
```

...is preferable to:

```
Entry.objects.create(headline='This is a test')
Entry.objects.create(headline='This is only a test')
```

Note that there are a number of [`caveats to this method`](/ja/3.1/ref/models/querysets/#django.db.models.query.QuerySet.bulk_create), so make sure it's appropriate
for your use case.

### Update in bulk

When updating objects, where possible, use the
[`bulk_update()`](/ja/3.1/ref/models/querysets/#django.db.models.query.QuerySet.bulk_update) method to reduce the
number of SQL queries. Given a list or queryset of objects:

```
entries = Entry.objects.bulk_create([
    Entry(headline='This is a test'),
    Entry(headline='This is only a test'),
])
```

The following example:

```
entries[0].headline = 'This is not a test'
entries[1].headline = 'This is no longer a test'
Entry.objects.bulk_update(entries, ['headline'])
```

...is preferable to:

```
entries[0].headline = 'This is not a test'
entries[0].save()
entries[1].headline = 'This is no longer a test'
entries[1].save()
```

Note that there are a number of [`caveats to this method`](/ja/3.1/ref/models/querysets/#django.db.models.query.QuerySet.bulk_update), so make sure it's appropriate
for your use case.

### Insert in bulk

When inserting objects into [`ManyToManyFields`](/ja/3.1/ref/models/fields/#django.db.models.ManyToManyField), use
[`add()`](/ja/3.1/ref/models/relations/#django.db.models.fields.related.RelatedManager.add) with multiple
objects to reduce the number of SQL queries. For example:

```
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.

When inserting different pairs of objects into
[`ManyToManyField`](/ja/3.1/ref/models/fields/#django.db.models.ManyToManyField) or when the custom
[`through`](/ja/3.1/ref/models/fields/#django.db.models.ManyToManyField.through) table is defined, use
[`bulk_create()`](/ja/3.1/ref/models/querysets/#django.db.models.query.QuerySet.bulk_create) method to reduce the
number of SQL queries. For example:

```
PizzaToppingRelationship = Pizza.toppings.through
PizzaToppingRelationship.objects.bulk_create([
    PizzaToppingRelationship(pizza=my_pizza, topping=pepperoni),
    PizzaToppingRelationship(pizza=your_pizza, topping=pepperoni),
    PizzaToppingRelationship(pizza=your_pizza, topping=mushroom),
], ignore_conflicts=True)
```

...is preferable to:

```
my_pizza.toppings.add(pepperoni)
your_pizza.toppings.add(pepperoni, mushroom)
```

...where `Pizza` and `Topping` have a many-to-many relationship. Note that
there are a number of [`caveats to this method`](/ja/3.1/ref/models/querysets/#django.db.models.query.QuerySet.bulk_create), so make sure it's appropriate
for your use case.

### Remove in bulk

When removing objects from [`ManyToManyFields`](/ja/3.1/ref/models/fields/#django.db.models.ManyToManyField), use
[`remove()`](/ja/3.1/ref/models/relations/#django.db.models.fields.related.RelatedManager.remove) with multiple
objects to reduce the number of SQL queries. For example:

```
my_band.members.remove(me, my_friend)
```

...is preferable to:

```
my_band.members.remove(me)
my_band.members.remove(my_friend)
```

...where `Bands` and `Artists` have a many-to-many relationship.

When removing different pairs of objects from [`ManyToManyFields`](/ja/3.1/ref/models/fields/#django.db.models.ManyToManyField), use
[`delete()`](/ja/3.1/ref/models/querysets/#django.db.models.query.QuerySet.delete) on a
[`Q`](/ja/3.1/ref/models/querysets/#django.db.models.Q) expression with multiple
[`through`](/ja/3.1/ref/models/fields/#django.db.models.ManyToManyField.through)  model instances to reduce
the number of SQL queries. For example:

```
from django.db.models import Q
PizzaToppingRelationship = Pizza.toppings.through
PizzaToppingRelationship.objects.filter(
    Q(pizza=my_pizza, topping=pepperoni) |
    Q(pizza=your_pizza, topping=pepperoni) |
    Q(pizza=your_pizza, topping=mushroom)
).delete()
```

...is preferable to:

```
my_pizza.toppings.remove(pepperoni)
your_pizza.toppings.remove(pepperoni, mushroom)
```

...where `Pizza` and `Topping` have a many-to-many relationship.
