select_related と prefetch_related で発行されるクエリを確認してみる
select_related と prefetch_related で発行されるクエリを確認してみる
とりあえず後日書き足せれば...
箇条書きで...
【モデル】
from django.db import models
class Writer(models.Model):
name = models.CharField(max_length=128)
class Publisher(models.Model):
name = models.CharField(max_length=128)
class Novel(models.Model):
title = models.CharField(max_length=512)
writer = models.ForeignKey(Writer, on_delete=models.CASCADE)
publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE)
class Comic(models.Model):
title = models.CharField(max_length=512)
writer = models.ForeignKey(Writer, on_delete=models.CASCADE)
publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE)
【データ】
myapp_writer
| id | name |
| --- | ------- |
| 1 | john |
| 2 | robert |
| 3 | michael |
| 4 | albert |
| 5 | ken |
myapp_publisher
| id | name |
| --- | ------------- |
| 1 | academic.inc |
| 2 | blackwell.inc |
| 3 | macmillan.inc |
| 4 | oxford.inc |
| 5 | thomason.inc |
myapp_novel
| id | title | publisher_id | writer_id |
| --- | ---------- | ------------ | --------- |
| 1 | happy_life | 1 | 5 |
| 2 | stay_here | 4 | 4 |
| 3 | great_day | 4 | 3 |
| 4 | the_world | 5 | 2 |
| 5 | my_life | 5 | 1 |
myapp_comic
| id | title | publisher_id | writer_id |
| --- | --------------- | ------------ | --------- |
| 1 | captain_america | 1 | 5 |
| 2 | iron_man | 2 | 5 |
| 3 | spider_man | 2 | 5 |
| 4 | hulk | 3 | 2 |
| 5 | dead_pool | 3 | 1 |
【ビュー】
from django.shortcuts import render
from django.db.models import Prefetch
from .models import Writer
from .models import Publisher
from .models import Novel
from .models import Comic
def index(request):
novel = Novel.objects.select_related('writer').get(id=1)
print(f'{novel.title} の著者は {novel.writer.name} です。')
# 結果
# happy_life の著者は ken です。
"""
SELECT
`myapp_novel`.`id`,
`myapp_novel`.`title`,
`myapp_novel`.`writer_id`,
`myapp_novel`.`publisher_id`,
`myapp_writer`.`id`,
`myapp_writer`.`name`
FROM
`myapp_novel`
INNER JOIN
`myapp_writer`
ON
(
`myapp_novel`.`writer_id` = `myapp_writer`.`id`
)
WHERE
`myapp_novel`.`id` = 1 LIMIT 21;
"""
novels = Novel.objects.select_related('writer').filter(title__contains='life')
for novel in novels:
print(f'タイトルに「life」がつくこの本 {novel.title} は {novel.writer.name} によって書かれました。')
# 結果
# タイトルに「life」がつくこの本 happy_life は ken によって書かれました。
# タイトルに「life」がつくこの本 my_life は john によって書かれました。
"""
SELECT
`myapp_novel`.`id`,
`myapp_novel`.`title`,
`myapp_novel`.`writer_id`,
`myapp_novel`.`publisher_id`,
`myapp_writer`.`id`,
`myapp_writer`.`name`
FROM
`myapp_novel`
INNER JOIN
`myapp_writer`
ON
(
`myapp_novel`.`writer_id` = `myapp_writer`.`id`
)
WHERE
`myapp_novel`.`title` LIKE BINARY '%life%'
LIMIT 21;
"""
novels = Novel.objects.select_related('writer').all()
for novel in novels:
print(f'{novel.title} は著者が {novel.writer.name} です。')
# 結果
# happy_life は著者が ken です。
# stay_here は著者が albert です。
# great_day は著者が michael です。
# the_world は著者が robert です。
# my_life は著者が john です。
"""
SELECT
`myapp_novel`.`id`,
`myapp_novel`.`title`,
`myapp_novel`.`writer_id`,
`myapp_novel`.`publisher_id`,
`myapp_writer`.`id`,
`myapp_writer`.`name`
FROM
`myapp_novel`
INNER JOIN
`myapp_writer`
ON
(
`myapp_novel`.`writer_id` = `myapp_writer`.`id`
);
"""
novels = Novel.objects.select_related('writer', 'publisher').all()
for novel in novels:
print(f'{novel.title} は著者が {novel.writer.name} で出版社は {novel.publisher.name} です。')
# 結果
# happy_life は著者が ken で出版社は academic.inc です。
# stay_here は著者が albert で出版社は oxford.inc です。
# great_day は著者が michael で出版社は oxford.inc です。
# the_world は著者が robert で出版社は thomson.inc です。
# my_life は著者が john で出版社は thomson.inc です。
"""
SELECT
`myapp_novel`.`id`,
`myapp_novel`.`title`,
`myapp_novel`.`writer_id`,
`myapp_novel`.`publisher_id`,
`myapp_writer`.`id`,
`myapp_writer`.`name`,
`myapp_publisher`.`id`,
`myapp_publisher`.`name`
FROM
`myapp_novel`
INNER JOIN
`myapp_writer`
ON
(
`myapp_novel`.`writer_id` = `myapp_writer`.`id`
)
INNER JOIN
`myapp_publisher`
ON
(
`myapp_novel`.`publisher_id` = `myapp_publisher`.`id`
)
LIMIT 21;
"""
writers = Writer.objects.prefetch_related('comic_set').all()
for writer in writers:
print(f'{writer.name} はコミックを {writer.comic_set.count()} 冊書きました。')
# 結果
# john はコミックを 1 冊書きました。
# robert はコミックを 1 冊書きました。
# michael はコミックを 0 冊書きました。
# albert はコミックを 0 冊書きました。
# ken はコミックを 3 冊書きました。
"""
SELECT
`myapp_writer`.`id`,
`myapp_writer`.`name`
FROM
`myapp_writer`
LIMIT 21;
SELECT
`myapp_comic`.`id`,
`myapp_comic`.`title`,
`myapp_comic`.`writer_id`,
`myapp_comic`.`publisher_id`
FROM
`myapp_comic`
WHERE
`myapp_comic`.`writer_id`
IN (1, 2, 3, 4, 5);
"""
writers = Writer.objects.prefetch_related('comic_set', 'novel_set').all()
for writer in writers:
print(f'{writer.name} はコミックを {writer.comic_set.count()} 冊、小説を {writer.comic_set.count()} 冊書きました。')
# 結果
# john はコミックを 1 冊、小説を 1 冊書きました。
# robert はコミックを 1 冊、小説を 1 冊書きました。
# michael はコミックを 0 冊、小説を 0 冊書きました。
# albert はコミックを 0 冊、小説を 0 冊書きました。
# ken はコミックを 3 冊、小説を 3 冊書きました。
"""
SELECT
`myapp_writer`.`id`,
`myapp_writer`.`name`
FROM
`myapp_writer`
LIMIT 21;
SELECT
`myapp_comic`.`id`,
`myapp_comic`.`title`,
`myapp_comic`.`writer_id`,
`myapp_comic`.`publisher_id`
FROM
`myapp_comic`
WHERE
`myapp_comic`.`writer_id`
IN (1, 2, 3, 4, 5);
SELECT
`myapp_novel`.`id`,
`myapp_novel`.`title`,
`myapp_novel`.`writer_id`,
`myapp_novel`.`publisher_id`
FROM
`myapp_novel`
WHERE
`myapp_novel`.`writer_id`
IN (1, 2, 3, 4, 5);
"""
writers = Writer.objects.prefetch_related(
Prefetch(
'comic_set', queryset=Comic.objects.select_related('publisher')
)
).all()
for writer in writers:
[print(f'{writer.name} は {comic.title} の出版を {comic.publisher.name} に依頼しました。') for comic in writer.comic_set.all()]
# 結果
# john は dead_pool の出版を macmillan.inc に依頼しました。
# robert は hulk の出版を macmillan.inc に依頼しました。
# ken は captain_america の出版を academic.inc に依頼しました。
# ken は iron_man の出版を blackwell.inc に依頼しました。
# ken は spider_man の出版を blackwell.inc に依頼しました。
"""
SELECT
`myapp_writer`.`id`,
`myapp_writer`.`name`
FROM
`myapp_writer` LIMIT 21;
SELECT
`myapp_comic`.`id`,
`myapp_comic`.`title`,
`myapp_comic`.`writer_id`,
`myapp_comic`.`publisher_id`,
`myapp_publisher`.`id`,
`myapp_publisher`.`name`
FROM
`myapp_comic`
INNER JOIN
`myapp_publisher`
ON
(
`myapp_comic`.`publisher_id` = `myapp_publisher`.`id`
)
WHERE
`myapp_comic`.`writer_id` IN (1, 2, 3, 4, 5);
"""
return render(request, 'myapp/index.html')
ディスカッション
コメント一覧
まだ、コメントがありません