0 / 0 / 1
Регистрация: 29.11.2012
Сообщений: 48
1

Graphql n+1 во вложенных запросах, даже с prefetch_related

26.09.2018, 17:11. Показов 566. Ответов 1

Всем привет, на проекте использую graphql из библиотеки graphene-django для django. И заметил такую не приятную проблему, если пытаться выбирать данные из вложенных во вложенных моделях, данные, то prefetch_related не работает.

Пример запрса:
JSON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
  cases {
    color
    id
    sef_url
    url
    caselanguge_set{
      title
    }
    block_set {
      blocklanguage_set{
        title
      }
      block_type {
        title
      }
    }
  }
}
Есть модель Case:
Python
1
2
3
4
5
6
7
8
9
10
class Case(models.Model):
    preview = models.ImageField(blank=False, width_field='image_width', height_field='image_height', verbose_name='Изображение для анонса')
    sef_url = models.CharField(max_length=255, blank=False, verbose_name='ЧПУ Ссылка')
    url = models.CharField(max_length=255, default='', blank=True, verbose_name='Ссылка')
    year = models.CharField(max_length=255, default='', blank=False, verbose_name='Год')
    color = models.CharField(max_length=255, default='', blank=False, verbose_name='Цвет')
    related_cases = models.ManyToManyField('self', blank=True, default='', verbose_name='Связанные кейсы')
    image_height = models.PositiveIntegerField(null=True, blank=True, editable=False, default="0", verbose_name='Высота изображения')
    image_width = models.PositiveIntegerField(null=True, blank=True, editable=False, default="0", verbose_name='Ширина изображения')
    created_at = models.DateTimeField(blank=False, verbose_name='Создан')
Есть модель Block:
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class BlockType(models.Model):
    title = models.CharField(max_length=255, blank=False, verbose_name='Заголовок')
 
    def __str__(self):
        return self.title
 
    class Meta:
        verbose_name = 'Тип блока'
        verbose_name_plural = 'Тип блоков'
 
 
class Block(models.Model):
    position = models.IntegerField(default=0, verbose_name='Расположение на странице')
    block_type = models.ForeignKey(
        BlockType,
        on_delete=models.CASCADE,
        verbose_name='Тип блока'
    )
    image = models.ImageField(width_field='image_width', height_field='image_height', verbose_name='Изображение')
    image_height = models.PositiveIntegerField(null=True, blank=True, editable=False, default="0", verbose_name='Высота')
    image_width = models.PositiveIntegerField(null=True, blank=True, editable=False, default="0", verbose_name='Ширина')
    case = models.ForeignKey(
        Case,
        on_delete=models.CASCADE,
        verbose_name='Кейс'
    )
Есть схема schame.py:
Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import graphene
from graphene_django.types import DjangoObjectType
from Case.models import Case, CaseLanguge
from Block.models import Block, BlockType, BlockLanguage
 
 
class CaseObject(DjangoObjectType):
    class Meta:
        model = Case
 
 
class CaseLanguageObject(DjangoObjectType):
    class Meta:
        model = CaseLanguge
 
 
class BlockTypeObject(DjangoObjectType):
    class Meta:
        model = BlockType
 
 
class BlockObject(DjangoObjectType):
    class Meta:
        model = Block
 
 
class BlockLanguageObject(DjangoObjectType):
    class Meta:
        model = BlockLanguage
 
 
class Query(graphene.ObjectType):
    cases = graphene.List(CaseObject)
    case_language = graphene.List(CaseObject)
    blocks = graphene.List(BlockObject)
 
    def resolve_cases(self, info, **kwargs):
        return Case.objects.slelect_related('block_set')\
                            .prefetch_related('related_cases',
                                              'tag_set',
                                              'caselanguge_set')
  
    def resolve_blocks(self, info, **kwargs):
        # We can easily optimize query count in the resolve method
        return Block.objects\
                            .prefetch_related('block_type')\
                            .prefetch_related('blocklanguage_set')
 
    
 
 
schema = graphene.Schema(query=Query, auto_camelcase=False)
Так вот при таком запросе, который описан выше, происходит аж 500 с лишним запросов в базу и все они связаны с block_type и block_language, а related_cases и case_language выбираются за 1 запрос.
Как сделать что бы и блоки тоже так же выбирались, в инете ничего внятного не нашел, думается, что так вообще нельзя.
0

Помощь в написании контрольных, курсовых и дипломных работ здесь.

Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
26.09.2018, 17:11
Ответы с готовыми решениями:

Именование столбцов во вложенных запросах
Здравствуйте, у меня есть такой запрос: SELECT top(50) g.inc_id, g.name,...

Delphi DB. Снова о вложенных запросах
Пересмотрел все темы по данному вопросу, ответа не нашел, поэтому попрошу помощи. Суть вопроса:...

Функции и Процедуры во вложенных запросах
Добрый день. Считал, что функции во вложенных запросах выполняются 1 раз, результат вычисления...

Отображение вложенных директорий без вложенных файлов (shlwapi.dll)
Здравствуйте. Вопрос: существует ли функция в shlwapi (или других библиотеках), позволяющая по...

1
0 / 0 / 1
Регистрация: 29.11.2012
Сообщений: 48
26.10.2018, 15:34  [ТС] 2
Так никто и не ответил, видать никому не приходилось с этим бороться. Вопрос решён, всё оказалось до безобразия просто
Python
1
2
3
4
cases = Case.objects.prefetch_related('blocks', 'blocks__block_type',
                                              'related_cases',
                                              'tags', 'tags__tag_category',
                                              'seos')
'blocks' - это связь с сущностью блоки, у которой есть своя связь block_type. И таким образом 170 запросов в базу превращаются в 7 запросов.
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
26.10.2018, 15:34

Помощь в написании контрольных, курсовых и дипломных работ здесь.

LIKE в запросах
Добрый вечер.Хочу сделать поиск по серверу,определенных фамилий.Надо сделать,чтобы Like работал...

Вычисление в запросах БД
Доброго времени суток! Помогите составить запрос для БД в которой ведется учет топлива. Есть...

Разница в запросах к бд ?
Подскажите что больше грузит систему ? такой запрос : mysql_fetch_array(mysql_query("SELECT...

Вычмсление в запросах
Добрый вечер! Вот код для вычисления возраста: ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
2
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.