{"title":"数据库连接优化","version":"2.2","locale":"zh-hans","docname":"topics/db/optimization","url":"/zh-hans/2.2/topics/db/optimization/","canonical":"https://djangodocs.dev/zh-hans/2.2/topics/db/optimization/","summary":"Django 的数据库层提供了很多方式，帮助开发者充分使用它们的数据库。本文收集连接至关联文档，并添加了很多技巧，这些技巧被组织在多个标题下，这些标题概述了优化数据库时要采取的步骤。 先介绍一下 Link to this heading # 作为一般的编程实践，这是不言而喻的。找出：ref:what queries you…","html":"<h1>数据库连接优化<a class=\"heading-anchor\" href=\"#database-access-optimization\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h1>\n<p>Django 的数据库层提供了很多方式，帮助开发者充分使用它们的数据库。本文收集连接至关联文档，并添加了很多技巧，这些技巧被组织在多个标题下，这些标题概述了优化数据库时要采取的步骤。</p>\n<section id=\"profile-first\">\n<h2>先介绍一下<a class=\"heading-anchor\" href=\"#profile-first\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>作为一般的编程实践，这是不言而喻的。找出：ref:what queries you are doing and what they are costing you &lt;faq-see-raw-sql-queries&gt;。用法：meth:.Queryset.explain`了解数据库如何执行特定的``Queryset`s。您可能还希望使用外部项目，<a class=\"reference external\" href=\"https://github.com/jazzband/django-debug-toolbar/\">如django-debug-toolbar</a>，或直接监视数据库的工具。</p>\n<p>请记住，根据您的需求，您可能正在优化速度或内存，或者两者兼而有之。有时，为一个优化会对另一个不利，但有时它们会互相帮助。另外，由数据库进程完成的工作可能与在Python进程中完成的工作量不同（对您来说）。这取决于您决定您的优先级是什么，平衡在哪里，并根据需要对所有这些进行分析，因为这将依赖于您的应用程序和服务器。</p>\n<p>对于接下来的所有内容，请记住在每次更改之后进行概要分析，以确保更改是一个好处，并且考虑到代码可读性的降低，这是一个足够大的好处。以下**所有**建议都附带警告，即在您的情况下，一般原则可能不适用，甚至可能被推翻。</p>\n</section>\n<section id=\"use-standard-db-optimization-techniques\">\n<h2>使用标准 DB 优化技巧<a class=\"heading-anchor\" href=\"#use-standard-db-optimization-techniques\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>……包括：</p>\n<ul class=\"simple\">\n<li><p><a class=\"reference external\" href=\"https://en.wikipedia.org/wiki/Database_index\">Indexes</a>。 这是第一优先级，在您通过分析应该添加哪些索引*之后*确定。 使用：attr:Meta.indexes &lt;django.db.models.Options.indexes&gt;`或：attr:`Field.db_index &lt;django.db.models.Field.db_index&gt;`从Django添加这些。 考虑将索引添加到您经常使用的字段：meth:`~django.db.models.query.QuerySet.filter（），：meth:~django.db.models.query.QuerySet.exclude（）， ：meth:<a href=\"#id1\"><span class=\"problematic\" id=\"id2\">`</span></a>~django.db.models.query.QuerySet.order_by（）`等作为索引可能有助于加快查找速度。 请注意，确定最佳索引是一个复杂的数据库相关主题，这依赖于您的特定应用程序。 维护索引的开销可能超过查询速度的任何增益。</p></li>\n</ul>\n<ul class=\"simple\">\n<li><p>合理使用字段类型。</p></li>\n</ul>\n<p>我们假设您已完成上述明显的事情。 本文档的其余部分重点介绍如何以不使用不必要的工作的方式使用Django。 本文档也没有涉及适用于所有昂贵操作的其他优化技术，例如：doc:general purpose caching&lt;/topics/cache&gt;。</p>\n</section>\n<section id=\"understand-querysets\">\n<h2>理解 <code class=\"docutils literal notranslate\"><span class=\"pre\">QuerySet</span></code><a class=\"heading-anchor\" href=\"#understand-querysets\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>理解 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/models/querysets/\"><span class=\"doc\">QuerySets</span></a> 是用简单代码获得高效率的关键。特别是在：</p>\n<section id=\"understand-queryset-evaluation\">\n<h3>理解 <code class=\"docutils literal notranslate\"><span class=\"pre\">QuerySet</span></code> 的执行过程<a class=\"heading-anchor\" href=\"#understand-queryset-evaluation\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>要避免执行过程中的问题，一定要理解：</p>\n<ul class=\"simple\">\n<li><p>:ref:QuertSets 是惰性的 &lt;querysets-are-lazy&gt;`。</p></li>\n<li><p>当 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/models/querysets/#when-querysets-are-evaluated\"><span class=\"std std-ref\">它们被计算时</span></a>。</p></li>\n<li><p>不过 <a class=\"reference internal\" href=\"/zh-hans/2.2/topics/db/queries/#caching-and-querysets\"><span class=\"std std-ref\">数据保存在内存中</span></a>。</p></li>\n</ul>\n</section>\n<section id=\"understand-cached-attributes\">\n<h3>理解缓存属性<a class=\"heading-anchor\" href=\"#understand-cached-attributes\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>除了缓存整个``QuerySet``之外，还有ORM对象上属性结果的缓存。 通常，将缓存不可调用的属性。 例如，假设：ref:example Weblog models&lt;queryset-model-example&gt;</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">entry</span> <span class=\"o\">=</span> <span class=\"n\">Entry</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"nb\">id</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">entry</span><span class=\"o\">.</span><span class=\"n\">blog</span>   <span class=\"c1\"># Blog object is retrieved at this point</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">entry</span><span class=\"o\">.</span><span class=\"n\">blog</span>   <span class=\"c1\"># cached version, no DB access</span>\n</code></pre></div>\n<p>但一般来说，callable 属性每次都会触发 DB 查询:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">entry</span> <span class=\"o\">=</span> <span class=\"n\">Entry</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"nb\">id</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">entry</span><span class=\"o\">.</span><span class=\"n\">authors</span><span class=\"o\">.</span><span class=\"n\">all</span><span class=\"p\">()</span>   <span class=\"c1\"># query performed</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">entry</span><span class=\"o\">.</span><span class=\"n\">authors</span><span class=\"o\">.</span><span class=\"n\">all</span><span class=\"p\">()</span>   <span class=\"c1\"># query performed again</span>\n</code></pre></div>\n<p>阅读模板代码时要小心 - 模板系统不允许使用括号，但会自动调用callables，隐藏上述区别。</p>\n<p>小心你自己的自定义属性 - 你需要在需要时实现缓存，例如使用：class:<a href=\"#id1\"><span class=\"problematic\" id=\"id2\">`</span></a>~django.utils.functional.cached_property`装饰器。</p>\n</section>\n<section id=\"use-the-with-template-tag\">\n<h3>使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">with</span></code> 模板标签<a class=\"heading-anchor\" href=\"#use-the-with-template-tag\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>要使用``QuerySet``的缓存行为，您可能需要使用：ttag:<a href=\"#id1\"><span class=\"problematic\" id=\"id2\">`</span></a>with`模板标记。</p>\n</section>\n<section id=\"use-iterator\">\n<h3>使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">iterator()</span></code><a class=\"heading-anchor\" href=\"#use-iterator\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>当你有很多对象时，<a href=\"#id1\"><span class=\"problematic\" id=\"id2\">``</span></a>QuerySet``的缓存行为会导致使用大量内存。 在这种情况下，：meth:<a href=\"#id3\"><span class=\"problematic\" id=\"id4\">`</span></a>~django.db.models.query.QuerySet.iterator()`可能有所帮助。</p>\n</section>\n<section id=\"use-explain\">\n<h3>使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">explain()</span></code><a class=\"heading-anchor\" href=\"#use-explain\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p><a class=\"reference internal\" href=\"/zh-hans/2.2/ref/models/querysets/#django.db.models.query.QuerySet.explain\" title=\"django.db.models.query.QuerySet.explain\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">QuerySet.explain()</span></code></a> 会有关于数据库如何执行查询的详细介绍，包括索引和联合(joins)的使用。这些细节可以帮助你如何更高效的重写查询，或者识别可以添加的所以来改进性能。</p>\n</section>\n</section>\n<section id=\"do-database-work-in-the-database-rather-than-in-python\">\n<h2>在数据库中执行数据库操作，而不是在 Python 代码中<a class=\"heading-anchor\" href=\"#do-database-work-in-the-database-rather-than-in-python\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>例子：</p>\n<ul class=\"simple\">\n<li><p>在最基础的层上，使用 filter 和 exclude 在数据库中过滤。</p></li>\n<li><p>使用 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/models/expressions/#django.db.models.F\" title=\"django.db.models.F\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">F</span> <span class=\"pre\">expressions</span></code></a> 来根据同一模型的其他字段进行过滤。</p></li>\n<li><p>利用 <a class=\"reference internal\" href=\"/zh-hans/2.2/topics/db/aggregation/\"><span class=\"doc\">注解在数据库中执行聚合</span></a>。</p></li>\n</ul>\n<p>若其不足以生成你需要的 SQL：</p>\n<section id=\"use-rawsql\">\n<h3>使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">RawSQL</span></code><a class=\"heading-anchor\" href=\"#use-rawsql\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>最简单直接的方法是 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/models/expressions/#django.db.models.expressions.RawSQL\" title=\"django.db.models.expressions.RawSQL\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">RawSQL</span></code></a> 表达式，它允许一些 SQL 显式的添加到查询中。如果这还不够强大：</p>\n</section>\n<section id=\"use-raw-sql\">\n<h3>使用原生 SQL<a class=\"heading-anchor\" href=\"#use-raw-sql\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>编写自定义的SQL来检索数据或填充模型。使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">django.db.connection.queries</span></code> 来找出 Django 为你编写的内容并从那里开始。</p>\n</section>\n</section>\n<section id=\"retrieve-individual-objects-using-a-unique-indexed-column\">\n<h2>使用唯一索引列来检索单个对象。<a class=\"heading-anchor\" href=\"#retrieve-individual-objects-using-a-unique-indexed-column\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>当使用 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/models/querysets/#django.db.models.query.QuerySet.get\" title=\"django.db.models.query.QuerySet.get\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">get()</span></code></a> 来检索单一对象时，使用 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/models/fields/#django.db.models.Field.unique\" title=\"django.db.models.Field.unique\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">unique</span></code></a> 或 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/models/fields/#django.db.models.Field.db_index\" title=\"django.db.models.Field.db_index\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">db_index</span></code></a> 的列有两个原因。首先，由于底层数据库索引，所以查询会更快。此外，如果多个对象与查找匹配，查询就会很慢。对列具有唯一约束保证不会发生这种情况。</p>\n<p>因此使用 <a class=\"reference internal\" href=\"/zh-hans/2.2/topics/db/queries/#queryset-model-example\"><span class=\"std std-ref\">example Weblog models</span></a>:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">entry</span> <span class=\"o\">=</span> <span class=\"n\">Entry</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"nb\">id</span><span class=\"o\">=</span><span class=\"mi\">10</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>会比以下更快：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">entry</span> <span class=\"o\">=</span> <span class=\"n\">Entry</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">headline</span><span class=\"o\">=</span><span class=\"s2\">&quot;News Item Title&quot;</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>因为 <code class=\"docutils literal notranslate\"><span class=\"pre\">id</span></code> 通过数据库索引，并且保证是唯一的。</p>\n<p>执行以下操作可能非常慢：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">entry</span> <span class=\"o\">=</span> <span class=\"n\">Entry</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">headline__startswith</span><span class=\"o\">=</span><span class=\"s2\">&quot;News&quot;</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>首先，<code class=\"docutils literal notranslate\"><span class=\"pre\">headline</span></code> 没有被索引，这将使得底层数据库获取变慢。</p>\n<p>其次，查找不保证只返回一个对象。如果查询匹配多于一个对象，它将从数据库中检索并传递所有对象。如果数据库位于单独的服务器上，那这个损失将更复杂，网络开销和延迟也是一个因素。</p>\n</section>\n<section id=\"retrieve-everything-at-once-if-you-know-you-will-need-it\">\n<h2>如果你明确需要它，那么立即检索所有内容。<a class=\"heading-anchor\" href=\"#retrieve-everything-at-once-if-you-know-you-will-need-it\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>对于你需要的所有部分的单个数据集的不同部分，多次访问数据库比单次查询所有内容的效率低。如果有一个查找，它在循环中执行，这点就尤其重要，当只需要一个查询时，最终会执行许多数据库查询。因此：</p>\n<section id=\"use-queryset-select-related-and-prefetch-related\">\n<h3>使用  <code class=\"docutils literal notranslate\"><span class=\"pre\">QuerySet.select_related()</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">prefetch_related()</span></code><a class=\"heading-anchor\" href=\"#use-queryset-select-related-and-prefetch-related\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>深入理解 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/models/querysets/#django.db.models.query.QuerySet.select_related\" title=\"django.db.models.query.QuerySet.select_related\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">select_related()</span></code></a> 和 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/models/querysets/#django.db.models.query.QuerySet.prefetch_related\" title=\"django.db.models.query.QuerySet.prefetch_related\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">prefetch_related()</span></code></a> ，并使用它们：</p>\n<ul class=\"simple\">\n<li><p>在 <a class=\"reference internal\" href=\"/zh-hans/2.2/topics/db/managers/\"><span class=\"doc\">managers and default managers</span></a> 中使用。请注意管理器何时被使用；有时这很棘手，所以不要做出假设。</p></li>\n<li><p>在视图代码层或其他层中，可能在需要时使用 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/models/querysets/#django.db.models.prefetch_related_objects\" title=\"django.db.models.prefetch_related_objects\"><code class=\"xref py py-func docutils literal notranslate\"><span class=\"pre\">prefetch_related_objects()</span></code></a> 。</p></li>\n</ul>\n</section>\n</section>\n<section id=\"don-t-retrieve-things-you-don-t-need\">\n<h2>不要检索你不需要的东西<a class=\"heading-anchor\" href=\"#don-t-retrieve-things-you-don-t-need\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<section id=\"use-queryset-values-and-values-list\">\n<h3>使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">QuerySet.values()</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">values_list()</span></code><a class=\"heading-anchor\" href=\"#use-queryset-values-and-values-list\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>当你只想得到字典或列表的值，并且不需要 ORM 模型对象时，可以适当使用 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/models/querysets/#django.db.models.query.QuerySet.values\" title=\"django.db.models.query.QuerySet.values\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">values()</span></code></a> 。这些对于替换模板代码中的模型对象非常有用——只要你提供的字典具有与模板中使用时相同的属性就行。</p>\n</section>\n<section id=\"use-queryset-defer-and-only\">\n<h3>使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">QuerySet.defer()</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">only()</span></code><a class=\"heading-anchor\" href=\"#use-queryset-defer-and-only\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>如果你明确不需要这个数据库列（或在大部分情况里不需要），使用 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/models/querysets/#django.db.models.query.QuerySet.defer\" title=\"django.db.models.query.QuerySet.defer\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">defer()</span></code></a> 和 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/models/querysets/#django.db.models.query.QuerySet.only\" title=\"django.db.models.query.QuerySet.only\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">only()</span></code></a> 来避免加载它们。注意如果你使用它们，ORM 将必须在单独的查询中获取它们，如果你不恰当的使用，会让事情变得糟糕。</p>\n<p>不要在没有分析的情况下过分使用延迟字段，因为数据库必须从磁盘中读取结果中单行的大部分非文本、非VARCHAR数据，即使它最终只使用的几列。当你不想加载许多文本数据或需要大量处理来转换回 Python的字段， <code class=\"docutils literal notranslate\"><span class=\"pre\">defer()</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">only()</span></code> 方法最有用。总之，先分析，再优化。</p>\n</section>\n<section id=\"use-queryset-count\">\n<h3>使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">QuerySet.count()</span></code><a class=\"heading-anchor\" href=\"#use-queryset-count\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>……如果你只想计数，不要使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">len(queryset)</span></code>。</p>\n</section>\n<section id=\"use-queryset-exists\">\n<h3>使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">QuerySet.exists()</span></code><a class=\"heading-anchor\" href=\"#use-queryset-exists\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>……若你只想要确认是否有至少存在一项满足条件的结果，而不是 <code class=\"docutils literal notranslate\"><span class=\"pre\">if</span> <span class=\"pre\">queryset</span></code>。</p>\n<p>但是：</p>\n</section>\n<section id=\"don-t-overuse-count-and-exists\">\n<span id=\"overuse-of-count-and-exists\"></span><h3>请不要过度使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">count()</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">exists()</span></code><a class=\"heading-anchor\" href=\"#don-t-overuse-count-and-exists\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>如果你需要查询集中的其他数据，请对其进行评估。</p>\n<p>比如，假设 Email 模型有 <code class=\"docutils literal notranslate\"><span class=\"pre\">body</span></code> 属性和与 User 的多对多关系 ，下面的模板代码是最佳的：</p>\n<div class=\"code-block\" data-language=\"html+django\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Django template</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Django template code\"><code><span class=\"cp\">{%</span> <span class=\"k\">if</span> <span class=\"nv\">display_inbox</span> <span class=\"cp\">%}</span>\n  <span class=\"cp\">{%</span> <span class=\"k\">with</span> <span class=\"nv\">emails</span><span class=\"o\">=</span><span class=\"nv\">user.emails.all</span> <span class=\"cp\">%}</span>\n    <span class=\"cp\">{%</span> <span class=\"k\">if</span> <span class=\"nv\">emails</span> <span class=\"cp\">%}</span>\n      <span class=\"p\">&lt;</span><span class=\"nt\">p</span><span class=\"p\">&gt;</span>You have <span class=\"cp\">{{</span> <span class=\"nv\">emails</span><span class=\"o\">|</span><span class=\"nf\">length</span> <span class=\"cp\">}}</span> email(s)<span class=\"p\">&lt;/</span><span class=\"nt\">p</span><span class=\"p\">&gt;</span>\n      <span class=\"cp\">{%</span> <span class=\"k\">for</span> <span class=\"nv\">email</span> <span class=\"k\">in</span> <span class=\"nv\">emails</span> <span class=\"cp\">%}</span>\n        <span class=\"p\">&lt;</span><span class=\"nt\">p</span><span class=\"p\">&gt;</span><span class=\"cp\">{{</span> <span class=\"nv\">email.body</span> <span class=\"cp\">}}</span><span class=\"p\">&lt;/</span><span class=\"nt\">p</span><span class=\"p\">&gt;</span>\n      <span class=\"cp\">{%</span> <span class=\"k\">endfor</span> <span class=\"cp\">%}</span>\n    <span class=\"cp\">{%</span> <span class=\"k\">else</span> <span class=\"cp\">%}</span>\n      <span class=\"p\">&lt;</span><span class=\"nt\">p</span><span class=\"p\">&gt;</span>No messages today.<span class=\"p\">&lt;/</span><span class=\"nt\">p</span><span class=\"p\">&gt;</span>\n    <span class=\"cp\">{%</span> <span class=\"k\">endif</span> <span class=\"cp\">%}</span>\n  <span class=\"cp\">{%</span> <span class=\"k\">endwith</span> <span class=\"cp\">%}</span>\n<span class=\"cp\">{%</span> <span class=\"k\">endif</span> <span class=\"cp\">%}</span>\n</code></pre></div>\n<p>这是最佳的，因为：</p>\n<ol class=\"arabic simple\">\n<li><p>因为查询集是懒加载，如果 'display_inbox' 是 False，就不会有数据库查询。</p></li>\n<li><p>使用 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/templates/builtins/#std-templatetag-with\"><code class=\"xref std std-ttag docutils literal notranslate\"><span class=\"pre\">with</span></code></a> 意味着我们在一个变量中存储 <code class=\"docutils literal notranslate\"><span class=\"pre\">user.emails.all</span></code> 以供日后使用，允许重用缓存。</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">{%</span> <span class=\"pre\">if</span> <span class=\"pre\">emails</span> <span class=\"pre\">%}</span></code> 会调用 <code class=\"docutils literal notranslate\"><span class=\"pre\">QuerySet.__bool__()</span></code> ，这会使得在数据库上执行 <code class=\"docutils literal notranslate\"><span class=\"pre\">user.emails.all()</span></code> 。如果没有结果，将返回 False，否则返回 True。</p></li>\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">{{</span> <span class=\"pre\">emails|length</span> <span class=\"pre\">}}</span></code> 会调用 <code class=\"docutils literal notranslate\"><span class=\"pre\">QuerySet.__len__()</span></code> ，填写剩余的缓存而不执行其他查询。</p></li>\n<li><p><a class=\"reference internal\" href=\"/zh-hans/2.2/ref/templates/builtins/#std-templatetag-for\"><code class=\"xref std std-ttag docutils literal notranslate\"><span class=\"pre\">for</span></code></a> 循环遍历已有的缓存。</p></li>\n</ol>\n<p>总之，这个代码会执行一条或零条数据库查询。唯一经过深思熟虑的优化是 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/templates/builtins/#std-templatetag-with\"><code class=\"xref std std-ttag docutils literal notranslate\"><span class=\"pre\">with</span></code></a> 标签。在任何时候使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">QuerySet.exists()</span></code> 或 <code class=\"docutils literal notranslate\"><span class=\"pre\">QuerySet.count()</span></code> 会导致额外的查询。</p>\n</section>\n<section id=\"use-queryset-update-and-delete\">\n<h3>使用 <code class=\"docutils literal notranslate\"><span class=\"pre\">QuerySet.update()</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">delete()</span></code><a class=\"heading-anchor\" href=\"#use-queryset-update-and-delete\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>如果要设置一些值并单独保存它们，而不是检索对象，那么可以通过 <a class=\"reference internal\" href=\"/zh-hans/2.2/topics/db/queries/#topics-db-queries-update\"><span class=\"std std-ref\">QuerySet.update()</span></a> 使用批量 SQL UPDATE 语句。类似地，尽可能使用批量删除（ <a class=\"reference internal\" href=\"/zh-hans/2.2/topics/db/queries/#topics-db-queries-delete\"><span class=\"std std-ref\">bulk deletes</span></a>  ）。</p>\n<p>注意，尽管这些批量更新方法不会调用单独实例的 <code class=\"docutils literal notranslate\"><span class=\"pre\">save()</span></code> 或 <code class=\"docutils literal notranslate\"><span class=\"pre\">delete()</span></code> 方法，这意味着你为这些方法添加的任何自定义行为都不会执行，包括来自正常数据库对象信号（ <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/signals/\"><span class=\"doc\">signals</span></a> ）的任何内容。</p>\n</section>\n<section id=\"use-foreign-key-values-directly\">\n<h3>直接使用外键值<a class=\"heading-anchor\" href=\"#use-foreign-key-values-directly\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>如果只需要外键值，那么使用已有对象上的外键值，而不是获取所有相关对象并获取它的主键。比如：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"n\">entry</span><span class=\"o\">.</span><span class=\"n\">blog_id</span>\n</code></pre></div>\n<p>替换成：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"n\">entry</span><span class=\"o\">.</span><span class=\"n\">blog</span><span class=\"o\">.</span><span class=\"n\">id</span>\n</code></pre></div>\n</section>\n<section id=\"don-t-order-results-if-you-don-t-care\">\n<h3>如无需要，不要排序结果<a class=\"heading-anchor\" href=\"#don-t-order-results-if-you-don-t-care\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>排序是耗时的；对每个字段的排序是数据库必须执行的操作。如果模型有一个默认排序（ <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/models/options/#django.db.models.Options.ordering\" title=\"django.db.models.Options.ordering\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">Meta.ordering</span></code></a> ）并且不需要它，那么可以通过调用没有参数的 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/models/querysets/#django.db.models.query.QuerySet.order_by\" title=\"django.db.models.query.QuerySet.order_by\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">order_by()</span></code></a> 在查询集上删除它。</p>\n<p>添加索引到你的数据库上可以帮助改进排序性能。</p>\n</section>\n</section>\n<section id=\"use-bulk-methods\">\n<h2>使用批量方法<a class=\"heading-anchor\" href=\"#use-bulk-methods\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>使用批量方法来减少 SQL 语句数量。</p>\n<section id=\"create-in-bulk\">\n<h3>批量创建<a class=\"heading-anchor\" href=\"#create-in-bulk\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>当创建对象时，尽可能使用 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/models/querysets/#django.db.models.query.QuerySet.bulk_create\" title=\"django.db.models.query.QuerySet.bulk_create\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">bulk_create()</span></code></a> 方法来减少 SQL 查询数量。比如：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"n\">Entry</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">bulk_create</span><span class=\"p\">([</span>\n    <span class=\"n\">Entry</span><span class=\"p\">(</span><span class=\"n\">headline</span><span class=\"o\">=</span><span class=\"s1\">&#39;This is a test&#39;</span><span class=\"p\">),</span>\n    <span class=\"n\">Entry</span><span class=\"p\">(</span><span class=\"n\">headline</span><span class=\"o\">=</span><span class=\"s1\">&#39;This is only a test&#39;</span><span class=\"p\">),</span>\n<span class=\"p\">])</span>\n</code></pre></div>\n<p>要优于：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"n\">Entry</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">create</span><span class=\"p\">(</span><span class=\"n\">headline</span><span class=\"o\">=</span><span class=\"s1\">&#39;This is a test&#39;</span><span class=\"p\">)</span>\n<span class=\"n\">Entry</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">create</span><span class=\"p\">(</span><span class=\"n\">headline</span><span class=\"o\">=</span><span class=\"s1\">&#39;This is only a test&#39;</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>注意这个方法有一些注意事项（ <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/models/querysets/#django.db.models.query.QuerySet.bulk_create\" title=\"django.db.models.query.QuerySet.bulk_create\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">caveats</span> <span class=\"pre\">to</span> <span class=\"pre\">this</span> <span class=\"pre\">method</span></code></a> ），因此要确保它适用于你的情况。</p>\n</section>\n<section id=\"update-in-bulk\">\n<h3>批量更新<a class=\"heading-anchor\" href=\"#update-in-bulk\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<aside class=\"version-note version-added\" data-version=\"2.2\">\n<p class=\"version-note-title\">New in Django 2.2</p></aside>\n<p>当更新对象时，尽可能使用 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/models/querysets/#django.db.models.query.QuerySet.bulk_update\" title=\"django.db.models.query.QuerySet.bulk_update\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">bulk_update()</span></code></a> 方法来减少 SQL 查询数。给定对象的列表或查询集：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"n\">entries</span> <span class=\"o\">=</span> <span class=\"n\">Entry</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">bulk_create</span><span class=\"p\">([</span>\n    <span class=\"n\">Entry</span><span class=\"p\">(</span><span class=\"n\">headline</span><span class=\"o\">=</span><span class=\"s1\">&#39;This is a test&#39;</span><span class=\"p\">),</span>\n    <span class=\"n\">Entry</span><span class=\"p\">(</span><span class=\"n\">headline</span><span class=\"o\">=</span><span class=\"s1\">&#39;This is only a test&#39;</span><span class=\"p\">),</span>\n<span class=\"p\">])</span>\n</code></pre></div>\n<p>下面示例：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"n\">entries</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">.</span><span class=\"n\">headline</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;This is not a test&#39;</span>\n<span class=\"n\">entries</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">.</span><span class=\"n\">headline</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;This is no longer a test&#39;</span>\n<span class=\"n\">Entry</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">bulk_update</span><span class=\"p\">(</span><span class=\"n\">entries</span><span class=\"p\">,</span> <span class=\"p\">[</span><span class=\"s1\">&#39;headline&#39;</span><span class=\"p\">])</span>\n</code></pre></div>\n<p>要优于：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"n\">entries</span><span class=\"p\">[</span><span class=\"mi\">0</span><span class=\"p\">]</span><span class=\"o\">.</span><span class=\"n\">headline</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;This is not a test&#39;</span>\n<span class=\"n\">entries</span><span class=\"o\">.</span><span class=\"n\">save</span><span class=\"p\">()</span>\n<span class=\"n\">entries</span><span class=\"p\">[</span><span class=\"mi\">1</span><span class=\"p\">]</span><span class=\"o\">.</span><span class=\"n\">headline</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;This is no longer a test&#39;</span>\n<span class=\"n\">entries</span><span class=\"o\">.</span><span class=\"n\">save</span><span class=\"p\">()</span>\n</code></pre></div>\n<p>注意此方法有一些 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/models/querysets/#django.db.models.query.QuerySet.bulk_update\" title=\"django.db.models.query.QuerySet.bulk_update\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">注意事项</span></code></a> ，因此确保它适合你的案例。</p>\n</section>\n<section id=\"insert-in-bulk\">\n<h3>批量插入<a class=\"heading-anchor\" href=\"#insert-in-bulk\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>当插入对象到 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/models/fields/#django.db.models.ManyToManyField\" title=\"django.db.models.ManyToManyField\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">ManyToManyFields</span></code></a> 时，使用带有多个对象的 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/models/relations/#django.db.models.fields.related.RelatedManager.add\" title=\"django.db.models.fields.related.RelatedManager.add\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">add()</span></code></a> 来减少 SQL 查询的数量。举例：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"n\">my_band</span><span class=\"o\">.</span><span class=\"n\">members</span><span class=\"o\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">me</span><span class=\"p\">,</span> <span class=\"n\">my_friend</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>要优于：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"n\">my_band</span><span class=\"o\">.</span><span class=\"n\">members</span><span class=\"o\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">me</span><span class=\"p\">)</span>\n<span class=\"n\">my_band</span><span class=\"o\">.</span><span class=\"n\">members</span><span class=\"o\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">my_friend</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>其中 <code class=\"docutils literal notranslate\"><span class=\"pre\">Bands</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">Artists</span></code> 有多对多关系。</p>\n<p>当不同的对象对插入到 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/models/fields/#django.db.models.ManyToManyField\" title=\"django.db.models.ManyToManyField\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">ManyToManyField</span></code></a> 或者自定义的 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/models/fields/#django.db.models.ManyToManyField.through\" title=\"django.db.models.ManyToManyField.through\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">through</span></code></a> 表被定义时，可以使用 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/models/querysets/#django.db.models.query.QuerySet.bulk_create\" title=\"django.db.models.query.QuerySet.bulk_create\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">bulk_create()</span></code></a> 方法来减少 SQL 查询的数量。比如：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"n\">PizzaToppingRelationship</span> <span class=\"o\">=</span> <span class=\"n\">Pizza</span><span class=\"o\">.</span><span class=\"n\">toppings</span><span class=\"o\">.</span><span class=\"n\">through</span>\n<span class=\"n\">PizzaToppingRelationship</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">bulk_create</span><span class=\"p\">([</span>\n    <span class=\"n\">PizzaToppingRelationship</span><span class=\"p\">(</span><span class=\"n\">pizza</span><span class=\"o\">=</span><span class=\"n\">my_pizza</span><span class=\"p\">,</span> <span class=\"n\">topping</span><span class=\"o\">=</span><span class=\"n\">pepperoni</span><span class=\"p\">),</span>\n    <span class=\"n\">PizzaToppingRelationship</span><span class=\"p\">(</span><span class=\"n\">pizza</span><span class=\"o\">=</span><span class=\"n\">your_pizza</span><span class=\"p\">,</span> <span class=\"n\">topping</span><span class=\"o\">=</span><span class=\"n\">pepperoni</span><span class=\"p\">),</span>\n    <span class=\"n\">PizzaToppingRelationship</span><span class=\"p\">(</span><span class=\"n\">pizza</span><span class=\"o\">=</span><span class=\"n\">your_pizza</span><span class=\"p\">,</span> <span class=\"n\">topping</span><span class=\"o\">=</span><span class=\"n\">mushroom</span><span class=\"p\">),</span>\n<span class=\"p\">],</span> <span class=\"n\">ignore_conflicts</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>要优于：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"n\">my_pizza</span><span class=\"o\">.</span><span class=\"n\">toppings</span><span class=\"o\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">pepperoni</span><span class=\"p\">)</span>\n<span class=\"n\">your_pizza</span><span class=\"o\">.</span><span class=\"n\">toppings</span><span class=\"o\">.</span><span class=\"n\">add</span><span class=\"p\">(</span><span class=\"n\">pepperoni</span><span class=\"p\">,</span> <span class=\"n\">mushroom</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>...其中 <code class=\"docutils literal notranslate\"><span class=\"pre\">Pizza</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">Topping</span></code> 是多对多关系。注意这里有一些注意事项（ <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/models/querysets/#django.db.models.query.QuerySet.bulk_create\" title=\"django.db.models.query.QuerySet.bulk_create\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">caveats</span> <span class=\"pre\">to</span> <span class=\"pre\">this</span> <span class=\"pre\">method</span></code></a> ），因此要确保它适用于你的案例。</p>\n</section>\n<section id=\"remove-in-bulk\">\n<h3>批量删除<a class=\"heading-anchor\" href=\"#remove-in-bulk\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>当从 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/models/fields/#django.db.models.ManyToManyField\" title=\"django.db.models.ManyToManyField\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">ManyToManyFields</span></code></a> 删除对象时，可以使用带有多个对象的 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/models/relations/#django.db.models.fields.related.RelatedManager.remove\" title=\"django.db.models.fields.related.RelatedManager.remove\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">remove()</span></code></a> 来减少 SQL 查询的数量。比如：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"n\">my_band</span><span class=\"o\">.</span><span class=\"n\">members</span><span class=\"o\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">me</span><span class=\"p\">,</span> <span class=\"n\">my_friend</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>要优于：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"n\">my_band</span><span class=\"o\">.</span><span class=\"n\">members</span><span class=\"o\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">me</span><span class=\"p\">)</span>\n<span class=\"n\">my_band</span><span class=\"o\">.</span><span class=\"n\">members</span><span class=\"o\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">my_friend</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>其中 <code class=\"docutils literal notranslate\"><span class=\"pre\">Bands</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">Artists</span></code> 有多对多关系。</p>\n<p>当从 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/models/fields/#django.db.models.ManyToManyField\" title=\"django.db.models.ManyToManyField\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">ManyToManyFields</span></code></a> 里删除不同的对象对时，可以在带有多种 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/models/fields/#django.db.models.ManyToManyField.through\" title=\"django.db.models.ManyToManyField.through\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">through</span></code></a> 模型实例的 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/models/querysets/#django.db.models.Q\" title=\"django.db.models.Q\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">Q</span></code></a> 表达式上使用 <a class=\"reference internal\" href=\"/zh-hans/2.2/ref/models/querysets/#django.db.models.query.QuerySet.delete\" title=\"django.db.models.query.QuerySet.delete\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">delete()</span></code></a> 来减少 SQL 查询的数量。比如：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.db.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Q</span>\n<span class=\"n\">PizzaToppingRelationship</span> <span class=\"o\">=</span> <span class=\"n\">Pizza</span><span class=\"o\">.</span><span class=\"n\">toppings</span><span class=\"o\">.</span><span class=\"n\">through</span>\n<span class=\"n\">PizzaToppingRelationship</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">filter</span><span class=\"p\">(</span>\n    <span class=\"n\">Q</span><span class=\"p\">(</span><span class=\"n\">pizza</span><span class=\"o\">=</span><span class=\"n\">my_pizza</span><span class=\"p\">,</span> <span class=\"n\">topping</span><span class=\"o\">=</span><span class=\"n\">pepperoni</span><span class=\"p\">)</span> <span class=\"o\">|</span>\n    <span class=\"n\">Q</span><span class=\"p\">(</span><span class=\"n\">pizza</span><span class=\"o\">=</span><span class=\"n\">your_pizza</span><span class=\"p\">,</span> <span class=\"n\">topping</span><span class=\"o\">=</span><span class=\"n\">pepperoni</span><span class=\"p\">)</span> <span class=\"o\">|</span>\n    <span class=\"n\">Q</span><span class=\"p\">(</span><span class=\"n\">pizza</span><span class=\"o\">=</span><span class=\"n\">your_pizza</span><span class=\"p\">,</span> <span class=\"n\">topping</span><span class=\"o\">=</span><span class=\"n\">mushroom</span><span class=\"p\">)</span>\n<span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">delete</span><span class=\"p\">()</span>\n</code></pre></div>\n<p>要优于：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"n\">my_pizza</span><span class=\"o\">.</span><span class=\"n\">toppings</span><span class=\"o\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">pepperoni</span><span class=\"p\">)</span>\n<span class=\"n\">your_pizza</span><span class=\"o\">.</span><span class=\"n\">toppings</span><span class=\"o\">.</span><span class=\"n\">remove</span><span class=\"p\">(</span><span class=\"n\">pepperoni</span><span class=\"p\">,</span> <span class=\"n\">mushroom</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>其中 <code class=\"docutils literal notranslate\"><span class=\"pre\">Pizza</span></code> 和 <code class=\"docutils literal notranslate\"><span class=\"pre\">Topping</span></code> 有多对多关系。</p>\n</section>\n</section>","rootId":"database-access-optimization","toc":[{"title":"先介绍一下","anchor":"profile-first","children":[]},{"title":"使用标准 DB 优化技巧","anchor":"use-standard-db-optimization-techniques","children":[]},{"title":"理解 QuerySet","anchor":"understand-querysets","children":[{"title":"理解 QuerySet 的执行过程","anchor":"understand-queryset-evaluation","children":[]},{"title":"理解缓存属性","anchor":"understand-cached-attributes","children":[]},{"title":"使用 with 模板标签","anchor":"use-the-with-template-tag","children":[]},{"title":"使用 iterator()","anchor":"use-iterator","children":[]},{"title":"使用 explain()","anchor":"use-explain","children":[]}]},{"title":"在数据库中执行数据库操作，而不是在 Python 代码中","anchor":"do-database-work-in-the-database-rather-than-in-python","children":[{"title":"使用 RawSQL","anchor":"use-rawsql","children":[]},{"title":"使用原生 SQL","anchor":"use-raw-sql","children":[]}]},{"title":"使用唯一索引列来检索单个对象。","anchor":"retrieve-individual-objects-using-a-unique-indexed-column","children":[]},{"title":"如果你明确需要它，那么立即检索所有内容。","anchor":"retrieve-everything-at-once-if-you-know-you-will-need-it","children":[{"title":"使用  QuerySet.select_related() 和 prefetch_related()","anchor":"use-queryset-select-related-and-prefetch-related","children":[]}]},{"title":"不要检索你不需要的东西","anchor":"don-t-retrieve-things-you-don-t-need","children":[{"title":"使用 QuerySet.values() 和 values_list()","anchor":"use-queryset-values-and-values-list","children":[]},{"title":"使用 QuerySet.defer() 和 only()","anchor":"use-queryset-defer-and-only","children":[]},{"title":"使用 QuerySet.count()","anchor":"use-queryset-count","children":[]},{"title":"使用 QuerySet.exists()","anchor":"use-queryset-exists","children":[]},{"title":"请不要过度使用 count() 和 exists()","anchor":"don-t-overuse-count-and-exists","children":[]},{"title":"使用 QuerySet.update() 和 delete()","anchor":"use-queryset-update-and-delete","children":[]},{"title":"直接使用外键值","anchor":"use-foreign-key-values-directly","children":[]},{"title":"如无需要，不要排序结果","anchor":"don-t-order-results-if-you-don-t-care","children":[]}]},{"title":"使用批量方法","anchor":"use-bulk-methods","children":[{"title":"批量创建","anchor":"create-in-bulk","children":[]},{"title":"批量更新","anchor":"update-in-bulk","children":[]},{"title":"批量插入","anchor":"insert-in-bulk","children":[]},{"title":"批量删除","anchor":"remove-in-bulk","children":[]}]}],"breadcrumbs":[{"docname":"topics/index","title":"使用 Django","url":"/zh-hans/2.2/topics/"},{"docname":"topics/db/index","title":"模型和数据库","url":"/zh-hans/2.2/topics/db/"}],"prev":{"docname":"topics/db/tablespaces","title":"表空间（Tablespaces）","url":"/zh-hans/2.2/topics/db/tablespaces/"},"next":{"docname":"topics/db/instrumentation","title":"数据库工具","url":"/zh-hans/2.2/topics/db/instrumentation/"},"formats":{"html":"/zh-hans/2.2/topics/db/optimization/","markdown":"/zh-hans/2.2/topics/db/optimization.md","json":"/zh-hans/2.2/topics/db/optimization.json"},"source":"https://github.com/django/django/blob/stable/2.2.x/docs/topics/db/optimization.txt","official":"https://docs.djangoproject.com/zh-hans/2.2/topics/db/optimization/","inVersions":["6.1","6.0","5.2","5.1","5.0","4.2","4.1","4.0","3.2","3.1","3.0","2.2","2.1","2.0"],"inLocales":["en","zh-hans","fr","ja","id","pt-br","ko","es","el","pl"]}