{"title":"데이터베이스 접근 최적화","version":"5.2","locale":"ko","docname":"topics/db/optimization","url":"/ko/5.2/topics/db/optimization/","canonical":"https://djangodocs.dev/ko/5.2/topics/db/optimization/","summary":"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…","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’s database layer provides various ways to help developers get the most\nout of their databases. This document gathers together links to the relevant\ndocumentation, and adds various tips, organized under a number of headings that\noutline the steps to take when attempting to optimize your database usage.</p>\n<section id=\"profile-first\">\n<h2>Profile first<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>As general programming practice, this goes without saying. Find out <a class=\"reference internal\" href=\"/ko/5.2/faq/models/#faq-see-raw-sql-queries\"><span class=\"std std-ref\">what\nqueries you are doing and what they are costing you</span></a>.\nUse <a class=\"reference internal\" href=\"/ko/5.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> to understand how specific <code class=\"docutils literal notranslate\"><span class=\"pre\">QuerySet</span></code>s are\nexecuted by your database. You may also want to use an external project like\n<a class=\"extlink-pypi reference external\" href=\"https://pypi.org/project/django-debug-toolbar/\">django-debug-toolbar</a>, or a tool that monitors your database directly.</p>\n<p>Remember that you may be optimizing for speed or memory or both, depending on\nyour requirements. Sometimes optimizing for one will be detrimental to the\nother, but sometimes they will help each other. Also, work that is done by the\ndatabase process might not have the same cost (to you) as the same amount of\nwork done in your Python process. It is up to you to decide what your\npriorities are, where the balance must lie, and profile all of these as required\nsince this will depend on your application and server.</p>\n<p>With everything that follows, remember to profile after every change to ensure\nthat the change is a benefit, and a big enough benefit given the decrease in\nreadability of your code. <strong>All</strong> of the suggestions below come with the caveat\nthat in your circumstances the general principle might not apply, or might even\nbe reversed.</p>\n</section>\n<section id=\"use-standard-db-optimization-techniques\">\n<h2>Use standard DB optimization techniques<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>…including:</p>\n<ul class=\"simple\">\n<li><p><a class=\"reference external\" href=\"https://en.wikipedia.org/wiki/Database_index\">Indexes</a>. This is a number one priority, <em>after</em> you have determined from\nprofiling what indexes should be added. Use\n<a class=\"reference internal\" href=\"/ko/5.2/ref/models/options/#django.db.models.Options.indexes\" title=\"django.db.models.Options.indexes\"><code class=\"xref py py-attr docutils literal notranslate\"><span class=\"pre\">Meta.indexes</span></code></a> or\n<a class=\"reference internal\" href=\"/ko/5.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\">Field.db_index</span></code></a> to add these from\nDjango. Consider adding indexes to fields that you frequently query using\n<a class=\"reference internal\" href=\"/ko/5.2/ref/models/querysets/#django.db.models.query.QuerySet.filter\" title=\"django.db.models.query.QuerySet.filter\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">filter()</span></code></a>,\n<a class=\"reference internal\" href=\"/ko/5.2/ref/models/querysets/#django.db.models.query.QuerySet.exclude\" title=\"django.db.models.query.QuerySet.exclude\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">exclude()</span></code></a>,\n<a class=\"reference internal\" href=\"/ko/5.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>, etc. as indexes may help\nto speed up lookups. Note that determining the best indexes is a complex\ndatabase-dependent topic that will depend on your particular application.\nThe overhead of maintaining an index may outweigh any gains in query speed.</p></li>\n</ul>\n<ul class=\"simple\">\n<li><p>Appropriate use of field types.</p></li>\n</ul>\n<p>We will assume you have done the things listed above. The rest of this document\nfocuses on how to use Django in such a way that you are not doing unnecessary\nwork. This document also does not address other optimization techniques that\napply to all expensive operations, such as <a class=\"reference internal\" href=\"/ko/5.2/topics/cache/\"><span class=\"doc\">general purpose caching</span></a>.</p>\n</section>\n<section id=\"understand-querysets\">\n<h2>Understand <code class=\"docutils literal notranslate\"><span class=\"pre\">QuerySet</span></code>s<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>Understanding <a class=\"reference internal\" href=\"/ko/5.2/ref/models/querysets/\"><span class=\"doc\">QuerySets</span></a> is vital to getting good\nperformance with simple code. In particular:</p>\n<section id=\"understand-queryset-evaluation\">\n<h3>Understand <code class=\"docutils literal notranslate\"><span class=\"pre\">QuerySet</span></code> evaluation<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>To avoid performance problems, it is important to understand:</p>\n<ul class=\"simple\">\n<li><p>that <a class=\"reference internal\" href=\"/ko/5.2/topics/db/queries/#querysets-are-lazy\"><span class=\"std std-ref\">QuerySets are lazy</span></a>.</p></li>\n<li><p>when <a class=\"reference internal\" href=\"/ko/5.2/ref/models/querysets/#when-querysets-are-evaluated\"><span class=\"std std-ref\">they are evaluated</span></a>.</p></li>\n<li><p>how <a class=\"reference internal\" href=\"/ko/5.2/topics/db/queries/#caching-and-querysets\"><span class=\"std std-ref\">the data is held in memory</span></a>.</p></li>\n</ul>\n</section>\n<section id=\"understand-cached-attributes\">\n<h3>Understand cached attributes<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>As well as caching of the whole <code class=\"docutils literal notranslate\"><span class=\"pre\">QuerySet</span></code>, there is caching of the result of\nattributes on ORM objects. In general, attributes that are not callable will be\ncached. For example, assuming the <a class=\"reference internal\" href=\"/ko/5.2/topics/db/queries/#queryset-model-example\"><span class=\"std std-ref\">example blog models</span></a>:</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</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=\"Python console 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>But in general, callable attributes cause DB lookups every time:</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</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=\"Python console 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>Be careful when reading template code - the template system does not allow use\nof parentheses, but will call callables automatically, hiding the above\ndistinction.</p>\n<p>Be careful with your own custom properties - it is up to you to implement\ncaching when required, for example using the\n<a class=\"reference internal\" href=\"/ko/5.2/ref/utils/#django.utils.functional.cached_property\" title=\"django.utils.functional.cached_property\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">cached_property</span></code></a> decorator.</p>\n</section>\n<section id=\"use-the-with-template-tag\">\n<h3>Use the <code class=\"docutils literal notranslate\"><span class=\"pre\">with</span></code> template tag<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>To make use of the caching behavior of <code class=\"docutils literal notranslate\"><span class=\"pre\">QuerySet</span></code>, you may need to use the\n<a class=\"reference internal\" href=\"/ko/5.2/ref/templates/builtins/#std-templatetag-with\"><code class=\"xref std std-ttag docutils literal notranslate\"><span class=\"pre\">with</span></code></a> template tag.</p>\n</section>\n<section id=\"use-iterator\">\n<h3>Use <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>When you have a lot of objects, the caching behavior of the <code class=\"docutils literal notranslate\"><span class=\"pre\">QuerySet</span></code> can\ncause a large amount of memory to be used. In this case,\n<a class=\"reference internal\" href=\"/ko/5.2/ref/models/querysets/#django.db.models.query.QuerySet.iterator\" title=\"django.db.models.query.QuerySet.iterator\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">iterator()</span></code></a> may help.</p>\n</section>\n<section id=\"use-explain\">\n<h3>Use <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=\"/ko/5.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> gives you detailed information about how the database\nexecutes a query, including indexes and joins that are used. These details may\nhelp you find queries that could be rewritten more efficiently, or identify\nindexes that could be added to improve performance.</p>\n</section>\n</section>\n<section id=\"do-database-work-in-the-database-rather-than-in-python\">\n<h2>Do database work in the database rather than in 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>For instance:</p>\n<ul class=\"simple\">\n<li><p>At the most basic level, use <a class=\"reference internal\" href=\"/ko/5.2/ref/models/querysets/#queryset-api\"><span class=\"std std-ref\">filter and exclude</span></a> to do\nfiltering in the database.</p></li>\n<li><p>Use <a class=\"reference internal\" href=\"/ko/5.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> to filter\nbased on other fields within the same model.</p></li>\n<li><p>Use <a class=\"reference internal\" href=\"/ko/5.2/topics/db/aggregation/\"><span class=\"doc\">annotate to do aggregation in the database</span></a>.</p></li>\n</ul>\n<p>If these aren’t enough to generate the SQL you need:</p>\n<section id=\"use-rawsql\">\n<h3>Use <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 less portable but more powerful method is the\n<a class=\"reference internal\" href=\"/ko/5.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> expression, which allows some SQL\nto be explicitly added to the query. If that still isn’t powerful enough:</p>\n</section>\n<section id=\"use-raw-sql\">\n<h3>Use raw 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>Write your own <a class=\"reference internal\" href=\"/ko/5.2/topics/db/sql/\"><span class=\"doc\">custom SQL to retrieve data or populate models</span></a>. Use <code class=\"docutils literal notranslate\"><span class=\"pre\">django.db.connection.queries</span></code> to find out what Django\nis writing for you and start from there.</p>\n</section>\n</section>\n<section id=\"retrieve-individual-objects-using-a-unique-indexed-column\">\n<h2>Retrieve individual objects using a unique, indexed column<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>There are two reasons to use a column with\n<a class=\"reference internal\" href=\"/ko/5.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> or\n<a class=\"reference internal\" href=\"/ko/5.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> when using\n<a class=\"reference internal\" href=\"/ko/5.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> to retrieve individual objects.\nFirst, the query will be quicker because of the underlying database index.\nAlso, the query could run much slower if multiple objects match the lookup;\nhaving a unique constraint on the column guarantees this will never happen.</p>\n<p>So using the <a class=\"reference internal\" href=\"/ko/5.2/topics/db/queries/#queryset-model-example\"><span class=\"std std-ref\">example blog models</span></a>:</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</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=\"Python console 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>will be quicker than:</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</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=\"Python console 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>because <code class=\"docutils literal notranslate\"><span class=\"pre\">id</span></code> is indexed by the database and is guaranteed to be unique.</p>\n<p>Doing the following is potentially quite slow:</p>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</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=\"Python console 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>First of all, <code class=\"docutils literal notranslate\"><span class=\"pre\">headline</span></code> is not indexed, which will make the underlying\ndatabase fetch slower.</p>\n<p>Second, the lookup doesn’t guarantee that only one object will be returned.\nIf the query matches more than one object, it will retrieve and transfer all of\nthem from the database. This penalty could be substantial if hundreds or\nthousands of records are returned. The penalty will be compounded if the\ndatabase lives on a separate server, where network overhead and latency also\nplay a factor.</p>\n</section>\n<section id=\"retrieve-everything-at-once-if-you-know-you-will-need-it\">\n<h2>Retrieve everything at once if you know you will need it<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>Hitting the database multiple times for different parts of a single ‘set’ of\ndata that you will need all parts of is, in general, less efficient than\nretrieving it all in one query. This is particularly important if you have a\nquery that is executed in a loop, and could therefore end up doing many database\nqueries, when only one was needed. So:</p>\n<section id=\"use-queryset-select-related-and-prefetch-related\">\n<h3>Use <code class=\"docutils literal notranslate\"><span class=\"pre\">QuerySet.select_related()</span></code> and <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>Understand <a class=\"reference internal\" href=\"/ko/5.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> and\n<a class=\"reference internal\" href=\"/ko/5.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> thoroughly, and use\nthem:</p>\n<ul class=\"simple\">\n<li><p>in <a class=\"reference internal\" href=\"/ko/5.2/topics/db/managers/\"><span class=\"doc\">managers and default managers</span></a> where\nappropriate. Be aware when your manager is and is not used; sometimes this is\ntricky so don’t make assumptions.</p></li>\n<li><p>in view code or other layers, possibly making use of\n<a class=\"reference internal\" href=\"/ko/5.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> where needed.</p></li>\n</ul>\n</section>\n</section>\n<section id=\"don-t-retrieve-things-you-don-t-need\">\n<h2>Don’t retrieve things you don’t need<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>Use <code class=\"docutils literal notranslate\"><span class=\"pre\">QuerySet.values()</span></code> and <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>When you only want a <code class=\"docutils literal notranslate\"><span class=\"pre\">dict</span></code> or <code class=\"docutils literal notranslate\"><span class=\"pre\">list</span></code> of values, and don’t need ORM model\nobjects, make appropriate usage of\n<a class=\"reference internal\" href=\"/ko/5.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>.\nThese can be useful for replacing model objects in template code - as long as\nthe dicts you supply have the same attributes as those used in the template,\nyou are fine.</p>\n</section>\n<section id=\"use-queryset-defer-and-only\">\n<h3>Use <code class=\"docutils literal notranslate\"><span class=\"pre\">QuerySet.defer()</span></code> and <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>Use <a class=\"reference internal\" href=\"/ko/5.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> and\n<a class=\"reference internal\" href=\"/ko/5.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> if there are database columns\nyou know that you won’t need (or won’t need in most cases) to avoid loading\nthem. Note that if you <em>do</em> use them, the ORM will have to go and get them in\na separate query, making this a pessimization if you use it inappropriately.</p>\n<p>Don’t be too aggressive in deferring fields without profiling as the database\nhas to read most of the non-text, non-<code class=\"docutils literal notranslate\"><span class=\"pre\">VARCHAR</span></code> data from the disk for a\nsingle row in the results, even if it ends up only using a few columns. The\n<code class=\"docutils literal notranslate\"><span class=\"pre\">defer()</span></code> and <code class=\"docutils literal notranslate\"><span class=\"pre\">only()</span></code> methods are most useful when you can avoid loading a\nlot of text data or for fields that might take a lot of processing to convert\nback to Python. As always, profile first, then optimize.</p>\n</section>\n<section id=\"use-queryset-contains-obj\">\n<h3>Use <code class=\"docutils literal notranslate\"><span class=\"pre\">QuerySet.contains(obj)</span></code><a class=\"heading-anchor\" href=\"#use-queryset-contains-obj\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>…if you only want to find out if <code class=\"docutils literal notranslate\"><span class=\"pre\">obj</span></code> is in the queryset, rather than\n<code class=\"docutils literal notranslate\"><span class=\"pre\">if</span> <span class=\"pre\">obj</span> <span class=\"pre\">in</span> <span class=\"pre\">queryset</span></code>.</p>\n</section>\n<section id=\"use-queryset-count\">\n<h3>Use <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>…if you only want the count, rather than doing <code class=\"docutils literal notranslate\"><span class=\"pre\">len(queryset)</span></code>.</p>\n</section>\n<section id=\"use-queryset-exists\">\n<h3>Use <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>…if you only want to find out if at least one result exists, rather than <code class=\"docutils literal notranslate\"><span class=\"pre\">if</span>\n<span class=\"pre\">queryset</span></code>.</p>\n<p>But:</p>\n</section>\n<section id=\"don-t-overuse-contains-count-and-exists\">\n<span id=\"overuse-of-count-and-exists\"></span><h3>Don’t overuse <code class=\"docutils literal notranslate\"><span class=\"pre\">contains()</span></code>, <code class=\"docutils literal notranslate\"><span class=\"pre\">count()</span></code>, and <code class=\"docutils literal notranslate\"><span class=\"pre\">exists()</span></code><a class=\"heading-anchor\" href=\"#don-t-overuse-contains-count-and-exists\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>If you are going to need other data from the QuerySet, evaluate it immediately.</p>\n<p>For example, assuming a <code class=\"docutils literal notranslate\"><span class=\"pre\">Group</span></code> model that has a many-to-many relation to\n<code class=\"docutils literal notranslate\"><span class=\"pre\">User</span></code>, the following code is optimal:</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\">members</span> <span class=\"o\">=</span> <span class=\"n\">group</span><span class=\"o\">.</span><span class=\"n\">members</span><span class=\"o\">.</span><span class=\"n\">all</span><span class=\"p\">()</span>\n\n<span class=\"k\">if</span> <span class=\"n\">display_group_members</span><span class=\"p\">:</span>\n    <span class=\"k\">if</span> <span class=\"n\">members</span><span class=\"p\">:</span>\n        <span class=\"k\">if</span> <span class=\"n\">current_user</span> <span class=\"ow\">in</span> <span class=\"n\">members</span><span class=\"p\">:</span>\n            <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s2\">&quot;You and&quot;</span><span class=\"p\">,</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">members</span><span class=\"p\">)</span> <span class=\"o\">-</span> <span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"s2\">&quot;other users are members of this group.&quot;</span><span class=\"p\">)</span>\n        <span class=\"k\">else</span><span class=\"p\">:</span>\n            <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s2\">&quot;There are&quot;</span><span class=\"p\">,</span> <span class=\"nb\">len</span><span class=\"p\">(</span><span class=\"n\">members</span><span class=\"p\">),</span> <span class=\"s2\">&quot;members in this group.&quot;</span><span class=\"p\">)</span>\n\n        <span class=\"k\">for</span> <span class=\"n\">member</span> <span class=\"ow\">in</span> <span class=\"n\">members</span><span class=\"p\">:</span>\n            <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"n\">member</span><span class=\"o\">.</span><span class=\"n\">username</span><span class=\"p\">)</span>\n    <span class=\"k\">else</span><span class=\"p\">:</span>\n        <span class=\"nb\">print</span><span class=\"p\">(</span><span class=\"s2\">&quot;There are no members in this group.&quot;</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>It is optimal because:</p>\n<ol class=\"arabic simple\">\n<li><p>Since QuerySets are lazy, this does no database queries if\n<code class=\"docutils literal notranslate\"><span class=\"pre\">display_group_members</span></code> is <code class=\"docutils literal notranslate\"><span class=\"pre\">False</span></code>.</p></li>\n<li><p>Storing <code class=\"docutils literal notranslate\"><span class=\"pre\">group.members.all()</span></code> in the <code class=\"docutils literal notranslate\"><span class=\"pre\">members</span></code> variable allows its\nresult cache to be reused.</p></li>\n<li><p>The line <code class=\"docutils literal notranslate\"><span class=\"pre\">if</span> <span class=\"pre\">members:</span></code> causes <code class=\"docutils literal notranslate\"><span class=\"pre\">QuerySet.__bool__()</span></code> to be called, which\ncauses the <code class=\"docutils literal notranslate\"><span class=\"pre\">group.members.all()</span></code> query to be run on the database. If there\naren’t any results, it will return <code class=\"docutils literal notranslate\"><span class=\"pre\">False</span></code>, otherwise <code class=\"docutils literal notranslate\"><span class=\"pre\">True</span></code>.</p></li>\n<li><p>The line <code class=\"docutils literal notranslate\"><span class=\"pre\">if</span> <span class=\"pre\">current_user</span> <span class=\"pre\">in</span> <span class=\"pre\">members:</span></code> checks if the user is in the result\ncache, so no additional database queries are issued.</p></li>\n<li><p>The use of <code class=\"docutils literal notranslate\"><span class=\"pre\">len(members)</span></code> calls <code class=\"docutils literal notranslate\"><span class=\"pre\">QuerySet.__len__()</span></code>, reusing the result\ncache, so again, no database queries are issued.</p></li>\n<li><p>The <code class=\"docutils literal notranslate\"><span class=\"pre\">for</span> <span class=\"pre\">member</span></code> loop iterates over the result cache.</p></li>\n</ol>\n<p>In total, this code does either one or zero database queries. The only\ndeliberate optimization performed is using the <code class=\"docutils literal notranslate\"><span class=\"pre\">members</span></code> variable. Using\n<code class=\"docutils literal notranslate\"><span class=\"pre\">QuerySet.exists()</span></code> for the <code class=\"docutils literal notranslate\"><span class=\"pre\">if</span></code>, <code class=\"docutils literal notranslate\"><span class=\"pre\">QuerySet.contains()</span></code> for the <code class=\"docutils literal notranslate\"><span class=\"pre\">in</span></code>,\nor <code class=\"docutils literal notranslate\"><span class=\"pre\">QuerySet.count()</span></code> for the count would each cause additional queries.</p>\n</section>\n<section id=\"use-queryset-update-and-delete\">\n<h3>Use <code class=\"docutils literal notranslate\"><span class=\"pre\">QuerySet.update()</span></code> and <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>Rather than retrieve a load of objects, set some values, and save them\nindividual, use a bulk SQL UPDATE statement, via <a class=\"reference internal\" href=\"/ko/5.2/topics/db/queries/#topics-db-queries-update\"><span class=\"std std-ref\">QuerySet.update()</span></a>. Similarly, do <a class=\"reference internal\" href=\"/ko/5.2/topics/db/queries/#topics-db-queries-delete\"><span class=\"std std-ref\">bulk deletes</span></a> where possible.</p>\n<p>Note, however, that these bulk update methods cannot call the <code class=\"docutils literal notranslate\"><span class=\"pre\">save()</span></code> or\n<code class=\"docutils literal notranslate\"><span class=\"pre\">delete()</span></code> methods of individual instances, which means that any custom\nbehavior you have added for these methods will not be executed, including\nanything driven from the normal database object <a class=\"reference internal\" href=\"/ko/5.2/ref/signals/\"><span class=\"doc\">signals</span></a>.</p>\n</section>\n<section id=\"use-foreign-key-values-directly\">\n<h3>Use foreign key values directly<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>If you only need a foreign key value, use the foreign key value that is already on\nthe object you’ve got, rather than getting the whole related object and taking\nits primary key. i.e. do:</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>Don’t order results if you don’t care<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>Ordering is not free; each field to order by is an operation the database must\nperform. If a model has a default ordering (<a class=\"reference internal\" href=\"/ko/5.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>) and you don’t need it, remove\nit on a <code class=\"docutils literal notranslate\"><span class=\"pre\">QuerySet</span></code> by calling\n<a class=\"reference internal\" href=\"/ko/5.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> with no parameters.</p>\n<p>Adding an index to your database may help to improve ordering performance.</p>\n</section>\n</section>\n<section id=\"use-bulk-methods\">\n<h2>Use bulk methods<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>Use bulk methods to reduce the number of SQL statements.</p>\n<section id=\"create-in-bulk\">\n<h3>Create in bulk<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>When creating objects, where possible, use the\n<a class=\"reference internal\" href=\"/ko/5.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> method to reduce the\nnumber of SQL queries. For example:</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=\"p\">[</span>\n        <span class=\"n\">Entry</span><span class=\"p\">(</span><span class=\"n\">headline</span><span class=\"o\">=</span><span class=\"s2\">&quot;This is a test&quot;</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=\"s2\">&quot;This is only a test&quot;</span><span class=\"p\">),</span>\n    <span class=\"p\">]</span>\n<span class=\"p\">)</span>\n</code></pre></div>\n<p>…is preferable to:</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=\"s2\">&quot;This is a test&quot;</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=\"s2\">&quot;This is only a test&quot;</span><span class=\"p\">)</span>\n</code></pre></div>\n<p>Note that there are a number of <a class=\"reference internal\" href=\"/ko/5.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>, so make sure it’s appropriate\nfor your use case.</p>\n</section>\n<section id=\"update-in-bulk\">\n<h3>Update in bulk<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<p>When updating objects, where possible, use the\n<a class=\"reference internal\" href=\"/ko/5.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> method to reduce the\nnumber of SQL queries. Given a list or queryset of objects:</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=\"p\">[</span>\n        <span class=\"n\">Entry</span><span class=\"p\">(</span><span class=\"n\">headline</span><span class=\"o\">=</span><span class=\"s2\">&quot;This is a test&quot;</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=\"s2\">&quot;This is only a test&quot;</span><span class=\"p\">),</span>\n    <span class=\"p\">]</span>\n<span class=\"p\">)</span>\n</code></pre></div>\n<p>The following example:</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=\"s2\">&quot;This is not a test&quot;</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=\"s2\">&quot;This is no longer a test&quot;</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=\"s2\">&quot;headline&quot;</span><span class=\"p\">])</span>\n</code></pre></div>\n<p>…is preferable to:</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=\"s2\">&quot;This is not a test&quot;</span>\n<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\">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=\"s2\">&quot;This is no longer a test&quot;</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\">save</span><span class=\"p\">()</span>\n</code></pre></div>\n<p>Note that there are a number of <a class=\"reference internal\" href=\"/ko/5.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\">caveats</span> <span class=\"pre\">to</span> <span class=\"pre\">this</span> <span class=\"pre\">method</span></code></a>, so make sure it’s appropriate\nfor your use case.</p>\n</section>\n<section id=\"insert-in-bulk\">\n<h3>Insert in bulk<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>When inserting objects into <a class=\"reference internal\" href=\"/ko/5.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>, use\n<a class=\"reference internal\" href=\"/ko/5.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> with multiple\nobjects to reduce the number of SQL queries. For example:</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>…is preferable to:</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>…where <code class=\"docutils literal notranslate\"><span class=\"pre\">Band</span></code> and <code class=\"docutils literal notranslate\"><span class=\"pre\">Artist</span></code> are models with a many-to-many relationship.</p>\n<p>When inserting different pairs of objects into\n<a class=\"reference internal\" href=\"/ko/5.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> or when the custom\n<a class=\"reference internal\" href=\"/ko/5.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> table is defined, use\n<a class=\"reference internal\" href=\"/ko/5.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> method to reduce the\nnumber of SQL queries. For example:</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=\"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>\n    <span class=\"n\">ignore_conflicts</span><span class=\"o\">=</span><span class=\"kc\">True</span><span class=\"p\">,</span>\n<span class=\"p\">)</span>\n</code></pre></div>\n<p>…is preferable to:</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>…where <code class=\"docutils literal notranslate\"><span class=\"pre\">Pizza</span></code> and <code class=\"docutils literal notranslate\"><span class=\"pre\">Topping</span></code> have a many-to-many relationship. Note that\nthere are a number of <a class=\"reference internal\" href=\"/ko/5.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>, so make sure it’s appropriate\nfor your use case.</p>\n</section>\n<section id=\"remove-in-bulk\">\n<h3>Remove in bulk<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>When removing objects from <a class=\"reference internal\" href=\"/ko/5.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>, use\n<a class=\"reference internal\" href=\"/ko/5.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> with multiple\nobjects to reduce the number of SQL queries. For example:</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>…is preferable to:</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>…where <code class=\"docutils literal notranslate\"><span class=\"pre\">Band</span></code> and <code class=\"docutils literal notranslate\"><span class=\"pre\">Artist</span></code> are models with a many-to-many relationship.</p>\n<p>When removing different pairs of objects from <a class=\"reference internal\" href=\"/ko/5.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>, use\n<a class=\"reference internal\" href=\"/ko/5.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> on a\n<a class=\"reference internal\" href=\"/ko/5.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> expression with multiple\n<a class=\"reference internal\" href=\"/ko/5.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>  model instances to reduce\nthe number of SQL queries. For example:</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\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>\n    <span class=\"o\">|</span> <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>\n    <span class=\"o\">|</span> <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>…is preferable to:</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>…where <code class=\"docutils literal notranslate\"><span class=\"pre\">Pizza</span></code> and <code class=\"docutils literal notranslate\"><span class=\"pre\">Topping</span></code> have a many-to-many relationship.</p>\n</section>\n</section>","rootId":"database-access-optimization","toc":[{"title":"Profile first","anchor":"profile-first","children":[]},{"title":"Use standard DB optimization techniques","anchor":"use-standard-db-optimization-techniques","children":[]},{"title":"Understand QuerySets","anchor":"understand-querysets","children":[{"title":"Understand QuerySet evaluation","anchor":"understand-queryset-evaluation","children":[]},{"title":"Understand cached attributes","anchor":"understand-cached-attributes","children":[]},{"title":"Use the with template tag","anchor":"use-the-with-template-tag","children":[]},{"title":"Use iterator()","anchor":"use-iterator","children":[]},{"title":"Use explain()","anchor":"use-explain","children":[]}]},{"title":"Do database work in the database rather than in Python","anchor":"do-database-work-in-the-database-rather-than-in-python","children":[{"title":"Use RawSQL","anchor":"use-rawsql","children":[]},{"title":"Use raw SQL","anchor":"use-raw-sql","children":[]}]},{"title":"Retrieve individual objects using a unique, indexed column","anchor":"retrieve-individual-objects-using-a-unique-indexed-column","children":[]},{"title":"Retrieve everything at once if you know you will need it","anchor":"retrieve-everything-at-once-if-you-know-you-will-need-it","children":[{"title":"Use QuerySet.select_related() and prefetch_related()","anchor":"use-queryset-select-related-and-prefetch-related","children":[]}]},{"title":"Don’t retrieve things you don’t need","anchor":"don-t-retrieve-things-you-don-t-need","children":[{"title":"Use QuerySet.values() and values_list()","anchor":"use-queryset-values-and-values-list","children":[]},{"title":"Use QuerySet.defer() and only()","anchor":"use-queryset-defer-and-only","children":[]},{"title":"Use QuerySet.contains(obj)","anchor":"use-queryset-contains-obj","children":[]},{"title":"Use QuerySet.count()","anchor":"use-queryset-count","children":[]},{"title":"Use QuerySet.exists()","anchor":"use-queryset-exists","children":[]},{"title":"Don’t overuse contains(), count(), and exists()","anchor":"don-t-overuse-contains-count-and-exists","children":[]},{"title":"Use QuerySet.update() and delete()","anchor":"use-queryset-update-and-delete","children":[]},{"title":"Use foreign key values directly","anchor":"use-foreign-key-values-directly","children":[]},{"title":"Don’t order results if you don’t care","anchor":"don-t-order-results-if-you-don-t-care","children":[]}]},{"title":"Use bulk methods","anchor":"use-bulk-methods","children":[{"title":"Create in bulk","anchor":"create-in-bulk","children":[]},{"title":"Update in bulk","anchor":"update-in-bulk","children":[]},{"title":"Insert in bulk","anchor":"insert-in-bulk","children":[]},{"title":"Remove in bulk","anchor":"remove-in-bulk","children":[]}]}],"breadcrumbs":[{"docname":"topics/index","title":"Django 사용하기","url":"/ko/5.2/topics/"},{"docname":"topics/db/index","title":"모델과 데이터베이스","url":"/ko/5.2/topics/db/"}],"prev":{"docname":"topics/db/tablespaces","title":"테이블스페이스","url":"/ko/5.2/topics/db/tablespaces/"},"next":{"docname":"topics/db/instrumentation","title":"Database instrumentation","url":"/ko/5.2/topics/db/instrumentation/"},"formats":{"html":"/ko/5.2/topics/db/optimization/","markdown":"/ko/5.2/topics/db/optimization.md","json":"/ko/5.2/topics/db/optimization.json"},"source":"https://github.com/django/django/blob/stable/5.2.x/docs/topics/db/optimization.txt","official":"https://docs.djangoproject.com/ko/5.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","1.11"],"inLocales":["en","sv","zh-hans","ga","fr","ja","id","it","pt-br","ko","es","el","pl"]}