Django ForeignKey逆引きクエリにおけるfilterと_setの効率比較
前文
Django を使ってモデルを作成する場合、しばしば ForeignKey を使って 2 つのテーブルの間に多対一の外部キー関係を作成します、例えば、B には
models.ForeignKey(A)
A.B_set.all()
または
B.objects.filter(A)
この2つは異なる方法です。
実際にサイトがオンラインになったとき、SEOはページの読み込み速度を重視し、増え続けるリクエストに直面したとき、この2つの方法のどちらが速いのか、という疑問も考えたことがあるのではないでしょうか?
という疑問が湧いてきたので、実行して見ます。 キュレーターはまだまだ未熟者なので、アカウントにログインして、間違っていたらコメントを残してください
実験環境
<ブロッククオート
オペレーティングシステム Manjaro Linux 17.1-rc2
Python パイソン 3.6.3
Django Django 1.11.7
データベース SQLite 3.21.0
CPU: i3-4130 @ 3.4GHz
メモリ DDR3 1600 8G + 4G
実験計画
個別の問題モデルの作成
Questions
と"answer"のモデルです。
Answers
回答モデルは質問モデルと多対一の関係を持っています
ForeignKey
質問と2つの回答を作成します。そして、2種類の方法でクエリーデータを1万回実行し、消費された時間を比較します。
実験的な実装
実験用モデルの作成
# myapp/models.py
from django.db import models
class Questions(models.Model):
'''Model of the question'''
title = models.CharField('title', max_length=100)
content = models.TextField('description')
class Answers(models.Model):
'''Model of answers'''
question = models.ForeignKey(Questions, on_delete=models.CASCADE, verbose_name='question')
content = models.TextField('answer')
それから、 django シェルに入って、モデルにデータを追加し、テストを書きます。
>>> from myapp.models import Questions, Answers
# Create the first question
Questions.objects.create(
title = 'Is this the first question?'
content = 'I think this is the first question, I don't know if it's true?'
)
# Create the first answer
Answers.objects.create(
question = Questions.objects.get(pk=1),
content = 'You're right, this is the first question'
)
# Create the second answer
Answers.objects.create(
question = Questions.objects.get(pk=1),
content = 'Question, you are the first question, but am I the second answer?'
)
timeitを使用して、両方のメソッドで消費される時間をテストします。
from timeit import timeit
# Build a function that uses the _set method
def time_test_1():
question = Question.objects.get(pk=1)
answers = question.answers_set.all()
# Construct a function that uses the filter method
def time_test_2():
question = Question.objects.get(pk=1)
answers = Answers.objects.filter(question=question)
# Use timeit to test 10000 times
timeit(time_test_1, number=10000)
5.346277045000534
timeit(time_test_2, number=10000)
5.11136907800028
実際に何度かテストしてみたところ、少なくとも私の使い方では、このように
A.B_set.all()
逆引きクエリは、常に
B.objects.filter(A)
フィルタリング方式では、約0.2〜0.3秒多く消費します。そのため、時間的なコストを考慮すると
filter
フィルタの方が効率的です。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
ハートビート・エフェクトのためのHTML+CSS
-
HTML ホテル フォームによるフィルタリング
-
HTML+cssのボックスモデル例(円、半円など)「border-radius」使いやすい
-
HTMLテーブルのテーブル分割とマージ(colspan, rowspan)
-
ランダム・ネームドロッパーを実装するためのhtmlサンプルコード
-
Html階層型ボックスシャドウ効果サンプルコード
-
QQの一時的なダイアログボックスをポップアップし、友人を追加せずにオンラインで話す効果を達成する方法
-
sublime / vscodeショートカットHTMLコード生成の実装
-
HTMLページを縮小した後にスクロールバーを表示するサンプルコード
-
html のリストボックス、テキストフィールド、ファイルフィールドのコード例