# Dokumentasi Django 6.0.7

# Optimisasi akses basisdata

Lapisan basisdata Django menyediakan beragam cara membantu pengembang mendapatkan sebagian dari basisdata mereka. DOkumen ini mengumpulkan bersama-sama tautan ke dokumentasi bersangkutan, dan menambah beraagam tip, mengorganisasikan dibawah sejumlah dari kepala yang meringkaskan langkah-langkah diambil ketika berusaha mengoptimalkan penggunaan basisdata anda.

## Profil dahulu

As general programming practice, this goes without saying. Find out what queries you are doing and what they are costing you. Use `QuerySet.explain()` to understand how specific `QuerySet`s are executed by your database. You may also want to use an external project like django-debug-toolbar, or a tool that monitors your database directly.

Ingat bahwa anda mungkin dioptimalkan untuk kecepatan atau memori atau keduanya, tergantung pada persyaraan anda. Terkadang mengoptimalkan untuk satu akan merugikan ke yang lain, tetapi terkadang mereka akan membantu satu sama lain. Juga, pekerjaan itu selesai oleh pengolahan basisdata mungkin tidak mempunyai biaya sama (kepada anda) seperti sama banyak dari pekerjaan selesai dalam pengolahan Python anda. Itu terserah anda memutuskan apa prioritas anda, dimana keseimbangan harus berbohong, dan profil semua dari ini seperti diwajibkan sejak ini akan bergantung pada aplikasi anda dan peladen.

Dengan apapun yang mengikuti, ingat untuk menggambarkan raut muka setelah setiap perubahan untuk memastikan bahwa perubahan adalah menguntungkan, dan keuntungan cukup besar diberikan menurunkan dalam kesiapan kode anda. Semua dari saran-saran dibawah datang dengan surat keberatan yang dalam keadaan anda prinsip umum mungkin tidak berlaku, atau mungkin bahkan dibalikkan.

## Gunakan teknik-teknik optimalisasi DB standar

...termasuk:

- Indexes. This is a number one priority, after you have determined from profiling what indexes should be added. Use `Meta.indexes` or `Field.db_index` to add these from Django. Consider adding indexes to fields that you frequently query using `filter()`, `exclude()`, `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.

- Penggunaan sesuai dari jenis-jenis bidang

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.

## Memahami `QuerySet`

Memahami QuerySets adalah vital untuk mendapatkan penampilan baik dengan kode sederhana. Khususnya:

### Memahami penilaian `QuerySet`

Untuk menghindari masalah penampilan, sangatlah penting memahami:

- itu QuerySets malas.

- ketika mereka dinilai.

- bagaimana data ditahan dalam memori.

### Memahami atribut tembolok

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 example blog models:

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

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

Hati-hati ketika membaca kode cetakan - sistem cetakan tidak mengizinkan penggunaan tanda kurun, tetapi akan memanggil callable secara otomatis, memnyembunyikan perbedaan diatas.

Berhati-hatilan dengan sifat penyesuaian anda sendiri - itu terserah anda menerapkan cache ketika dibutuhkan, sebagai contoh menggunakan penghias `cached_property`.

### Gunakan etiket cetakan `with`

Untuk menggunakan perilaku cache dari `QuerySet`, anda mungkin butuh menggunakan etiket cetakan `with`.

### Gunakan `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, `iterator()` may help.

### Gunakan `explain()`

`QuerySet.explain()` gives you detailed information about how the database executes a query, including indexes and joins that are used. These details may help you find queries that could be rewritten more efficiently, or identify indexes that could be added to improve performance.

## Lakukan pekerjaan basisdata di basisdata daripada di Python

Sebagai contoh:

- Pada paling tingkat dasar, gunakan filter and exclude melakukan penyaringan di basisdata

- Use Pernyataan F() to filter based on other fields within the same model.

- Gunakan annotate to do aggregation in the database.

Jika ini tidak cukup membangkitkan SQL yang anda butuhkan:

### Gunakan `RawSQL`

Sedikit ringan tetapi metode lebih kuat adalah pernyataan `RawSQL`, yangmengizinkan beberapa SQL secara jelas ditambahkan ke permintaan. Jika itu masih tidak cukup kuat:

### Gunakan SQL mentah

Tulis custom SQL to retrieve data or populate models 1 anda sendiri. Gunakan `django.db.connection.queries` untuk menemukan apa yang Django sedang tulis untuk anda dan mulai dari sana.

## Mengambil obyek tersendiri menggukan sebuah unik, kolom indeks

Ada dua alasan untuk menggunakan kolom dengan `unique` atau `db_index` ketika menggunakan `get()` untuk mengambil obyek tersendiri. Pertama, permintaan akan lebih cepat karena indeks basisdata pokok. Juga, permintaan dapat berjalan lebih lambat jika banyak obyek mencocokan pencarian; memiliki batasan unik pada kolom menjamin ini tidak pernah terjadi.

So using the example blog models:

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

akan lebih cepat daripada:

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

karena `id` diindeks oleh basisdata dan dijamin menjadi unik.

Melakukan berikut berpotensi sangat lambat:

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

Pertama-tama, `headline` tidak diindeks, yang akan membuat pengambilan pokok basisdata lebih lambat.

Second, the lookup may return multiple results. Even though Django applies a limit of 21 objects when using `get()`, the database may still need to scan everything to evaluate a non-unique condition. Narrowing your query up-front is more efficient.

## Retrieve related objects efficiently

Generally, accessing the database multiple times to retrieve different parts of a single "set" of data is 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 is needed. Below are some techniques to combine queries for efficiency.

### Use the `FETCH_PEERS` fetch mode

Use the `FETCH_PEERS` fetch mode to make on-demand field access more efficient with bulk-fetching. Enable it for all usage of your models with a custom manager.

Using this fetch mode is easier than declaring fields to fetch with `select_related()` or `prefetch_related()`, especially when it's hard to predict which fields will be accessed.

### Gunakan `QuerySet.select_related()` dan `prefetch_related()`

When the `FETCH_PEERS` fetch mode is not appropriate or efficient enough, use `select_related()` and `prefetch_related()`. Understand their documentation thoroughly and apply them where needed.

It may be useful to apply these methods in managers and default managers. Be aware when your manager is and is not used; for example, related object access uses the base manager rather than the default manager.

### Use `prefetch_related_objects()`

Where `prefetch_related` would be useful after the queryset has been evaluated, use `prefetch_related_objects()` to execute an extra prefetch.

## Jangan mengambil hal yang tidak anda butuhkan

### Gunakan `QuerySet.values()` dan `values_list()`

When you only want a `dict` or `list` of values, and don't need ORM model objects, make appropriate usage of `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.

### Gunakan `QuerySet.defer()` dan `only()`

Use `defer()` and `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.contains(obj)`

...if you only want to find out if `obj` is in the queryset, rather than `if obj in queryset`.

### Gunakan `QuerySet.count()`

..jika anda hanya ingin menghitung, daripada melakukan `len(queryset)`.

### Gunakan `QuerySet.exists()`

...jika anda hanya ingin menemukan jika setidaknya satu hasil ada, daripada `if queryset`.

Tetapi:

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

Jika anda butuh data lain dari QuerySet, nilai itu segera.

For example, assuming a `Group` model that has a many-to-many relation to `User`, the following code is optimal:

    members = group.members.all()

    if display_group_members:
        if members:
            if current_user in members:
                print("You and", len(members) - 1, "other users are members of this group.")
            else:
                print("There are", len(members), "members in this group.")

            for member in members:
                print(member.username)
        else:
            print("There are no members in this group.")

DIa optimal karena:

1. Since QuerySets are lazy, this does no database queries if `display_group_members` is `False`.

2. Storing `group.members.all()` in the `members` variable allows its result cache to be reused.

3. The line `if members:` causes `QuerySet.__bool__()` to be called, which causes the `group.members.all()` query to be run on the database. If there aren't any results, it will return `False`, otherwise `True`.

4. The line `if current_user in members:` checks if the user is in the result cache, so no additional database queries are issued.

5. The use of `len(members)` calls `QuerySet.__len__()`, reusing the result cache, so again, no database queries are issued.

6. The `for member` loop iterates over the result cache.

In total, this code does either one or zero database queries. The only deliberate optimization performed is using the `members` variable. Using `QuerySet.exists()` for the `if`, `QuerySet.contains()` for the `in`, or `QuerySet.count()` for the count would each cause additional queries.

### Gunakan `QuerySet.update()` dan `delete()`

Daripada mengambil memuat obyek, setel beberapa nilai, dan simpan mereka masing-masing, gunakan pernyataan SQL UPDATE dalam jumlah besar, melalui QuerySet.update() 1. Demikian pula, lakukan bulk deletes 2 dimana memungkinkan.

Catat, bagaimanapun, metode pembaharuan jumlah besar ini tidak dapat memanggil metode `save()` atau `delete()` dari masing-masing instance, yang berarti bahwa perilaku penyesuaian apapun anda telah tambahkan untuk metode-metode ini tidak akan dijalankan, termasuk apapun didorong dari obyek basisdata biasa signals 1.

### Menggunakan nilai foreign key secara langsung

Jika anda hanya butuh nilai foreign key, gunakan nilai foreign key yang sudah pada obyek anda telah dapatkan, daripada mendapatkan keseluruhan obyek terkait dan mengambil primary key nya, yaitu. lakukan:

    entry.blog_id

dari pada:

    entry.blog.id

### Jangan urutkan hasil jika anda tidak peduli

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`) and you don't need it, remove it on a `QuerySet` by calling `order_by()` with no parameters.

Menambahkan indeks ke basisdata anda mungkin membantu meningkatkan penampilan pengurutan.

## 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()` 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"),
        ]
    )

...adalah lebih baik untuk:

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

Note that `bulk_create()` has several caveats, so ensure it's appropriate for your use case.

### Update in bulk

When updating objects, where possible, use the `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"),
        ]
    )

Contoh berikut:

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

...adalah lebih baik untuk:

    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 `bulk_update()` has several caveats, so ensure it's appropriate for your use case.

### Masuk dalam bulk

When inserting objects into `ManyToManyFields`, use `add()` with multiple objects to reduce the number of SQL queries. For example:

    my_band.members.add(me, my_friend)

...adalah lebih baik untuk:

    my_band.members.add(me)
    my_band.members.add(my_friend)

...where `Band` and `Artist` are models with a many-to-many relationship.

When inserting different pairs of objects into `ManyToManyField` or when the custom `through` table is defined, use `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,
    )

...adalah lebih baik untuk:

    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`, so make sure it's appropriate for your use case.

### Remove in bulk

When removing objects from `ManyToManyFields`, use `remove()` with multiple objects to reduce the number of SQL queries. For example:

    my_band.members.remove(me, my_friend)

...adalah lebih baik untuk:

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

...where `Band` and `Artist` are models with a many-to-many relationship.

When removing multiple many-to-many relationships involving several instances of the related models, use the `delete()` method on a filtered queryset of the field's `through` model. By combining multiple conditions with Obyek Q(), you can delete several relationships in a single query. 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()

...adalah lebih baik untuk:

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

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