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

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

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

Author24 — интернет-сервис помощи студентам
Всем привет, на проекте использую 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
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
26.09.2018, 17:11
Ответы с готовыми решениями:

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

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

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

1
 Аватар для kadr
0 / 0 / 1
Регистрация: 29.11.2012
Сообщений: 48
26.10.2018, 15:34  [ТС]
Так никто и не ответил, видать никому не приходилось с этим бороться. Вопрос решён, всё оказалось до безобразия просто
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
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
26.10.2018, 15:34
Помогаю со студенческими работами здесь

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

graphql mutation
Можете помочь составить мутацию? type Mutation { createCustomMatch(input: CreateCustomMatchInput!): Int } input...

MeteorJS и GraphQL
Привет, Хочу сказать что до недавнего времени MeteorJS и GraphQL являются какойто мутью в голове. И я встречаю людей которые говорят...

Работа с Graphql
Добрый день! Начал пробовать работать с graphql (сайт, который пытаюсь спарсить имеет такой тип API). Есть ли возможность как-то...

Не вся ОЗУ видна х32 даже 4 ГБ видно 2.7 Даже не 3-3,2
Я поискал в гугле и понял что х32 битная система не видит все 4 ГБ из установленных 4гб но на разных ресурсах написано что ОЗУ может там...


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

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

Новые блоги и статьи
Реализация многопоточных сетевых серверов на Python
py-thonny 16.05.2025
Когда сталкиваешься с необходимостью писать высоконагруженные сетевые сервисы, выбор технологии имеет критическое значение. Python, со своей элегантностью и высоким уровнем абстракции, может. . .
C# и IoT: разработка Edge приложений с .NET и Azure IoT
UnmanagedCoder 16.05.2025
Мир меняется прямо на наших глазах, и интернет вещей (IoT) — один из главных катализаторов этих перемен. Если всего десять лет назад концепция "умных" устройств вызывала скептические улыбки, то. . .
Гибридные квантово-классические вычисления: Примеры оптимизации
EggHead 16.05.2025
Гибридные квантово-классические вычисления — это настоящий прорыв в подходах к решению сложнейших вычислительных задач. Представьте себе союз двух разных миров: классические компьютеры, с их. . .
Использование вебсокетов в приложениях Java с Netty
Javaican 16.05.2025
HTTP, краеугольный камень интернета, изначально был спроектирован для передачи гипертекста с минимальной интерактивностью. Его главный недостаток в контексте современных приложений — это. . .
Реализация операторов Kubernetes
Mr. Docker 16.05.2025
Концепция операторов Kubernetes зародилась в недрах компании CoreOS (позже купленной Red Hat), когда команда инженеров искала способ автоматизировать управление распределёнными базами данных в. . .
Отражение в C# и динамическое управление типами
stackOverflow 16.05.2025
Reflection API в . NET — это набор классов и интерфейсов в пространстве имён System. Reflection, который позволяет исследовать и манипулировать типами, методами, свойствами и другими элементами. . .
Настройка гиперпараметров с помощью Grid Search и Random Search в Python
AI_Generated 15.05.2025
В машинном обучении существует фундаментальное разделение между параметрами и гиперпараметрами моделей. Если параметры – это те величины, которые алгоритм "изучает" непосредственно из данных (веса. . .
Сериализация и десериализация данных на Python
py-thonny 15.05.2025
Сериализация — это своего рода "замораживание" объектов. Вы берёте живой, динамический объект из памяти и превращаете его в статичную строку или поток байтов. А десериализация выполняет обратный. . .
Чем асинхронная логика (схемотехника) лучше тактируемой, как я думаю, что помимо энергоэффективности - ещё и безопасность.
Hrethgir 14.05.2025
Помимо огромного плюса в энергоэффективности, асинхронная логика - тотальный контроль над каждым совершённым тактом, а значит - безусловная безопасность, где безконтрольно не совершится ни одного. . .
Многопоточные приложения на C++
bytestream 14.05.2025
C++ всегда был языком, тесно работающим с железом, и потому особеннно эффективным для многопоточного программирования. Стандарт C++11 произвёл революцию, добавив в язык нативную поддержку потоков,. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru