Я боролся с проблемой, которую, я думаю, каждый делает в какой-то момент.У меня пока есть небольшая база данных из 150 тыс. Товаров.(Увеличивается, когда я пишу это.)
Я использую DRF для API и борюсь с производительностью категорий, в которых у меня много продуктов.
IE у меня естькатегория называется платья, которые имеют 34633
продуктов.Как устроена моя база данных, у меня есть пара отношений под ней.
Продукт имеет категории, атрибуты, цвет, размеры, сопутствующие товары M2M
Запросы
Количество запросов 809.83
мс
SELECT COUNT(*)
FROM (
SELECT DISTINCT `catalog_products`.`id` AS Col1
FROM `catalog_products`
INNER JOIN `catalog_products_category` ON (`catalog_products`.`id` =
`catalog_products_category`.`products_id`)
WHERE (`catalog_products`.`deleted` = 0
AND `catalog_products`.`in_stock` = 1
AND `catalog_products_category`.`categories_id` = 183)
) subquery
Результат запроса 2139.52
мс
SELECT DISTINCT `catalog_products`.`id`, `catalog_products`.`sku`,
`catalog_products`.`title`, `catalog_products`.`old_price`,
`catalog_products`.`price`, `catalog_products`.`sale`,
`catalog_products`.`original_categories`,
`catalog_products`.`original_conv_color`, `catalog_products`.`original_sizes`
FROM `catalog_products`
INNER JOIN `catalog_products_category` ON (`catalog_products`.`id` =
`catalog_products_category`.`products_id`)
WHERE (`catalog_products`.`deleted` = 0
AND `catalog_products`.`in_stock` = 1
AND `catalog_products_category`.`categories_id` = 183)
ORDER BY `catalog_products`.`title` ASC LIMIT 48
как вы можетеПосмотрим, сколько времени для запроса, но вот сложная часть, когда я применяю фильтры IE. Я выбираю цветной фильтр, и время начала уменьшаться.
Запросы с примененными фильтрами
Количество запросов 264.63
мс
SELECT COUNT(*) FROM (
SELECT DISTINCT `catalog_products`.`id` AS Col1
FROM `catalog_products`
INNER JOIN `catalog_products_color` ON (`catalog_products`.`id` =
`catalog_products_color`.`products_id`)
INNER JOIN `catalog_products_category` ON (`catalog_products`.`id` =
`catalog_products_category`.`products_id`)
INNER JOIN `catalog_sizethrough` ON (`catalog_products`.`id` =
`catalog_sizethrough`.`product_id`)
WHERE (`catalog_products`.`deleted` = 0
AND `catalog_products`.`in_stock` = 1
AND `catalog_products_color`.`color_id` = 1
AND `catalog_products_category`.`categories_id` = 183
AND `catalog_sizethrough`.`size_id` IN (262)
AND `catalog_sizethrough`.`stock` = 1)
) subquery
Результат запроса 351.43
мс
SELECT DISTINCT `catalog_products`.`id`, `catalog_products`.`sku`,
`catalog_products`.`title`, `catalog_products`.`old_price`,
`catalog_products`.`price`, `catalog_products`.`sale`,
`catalog_products`.`original_categories`,
`catalog_products`.`original_conv_color`,
`catalog_products`.`original_sizes`
FROM `catalog_products`
INNER JOIN `catalog_products_color` ON (`catalog_products`.`id` =
`catalog_products_color`.`products_id`)
INNER JOIN `catalog_products_category` ON (`catalog_products`.`id` =
`catalog_products_category`.`products_id`)
INNER JOIN `catalog_sizethrough` ON (`catalog_products`.`id` =
`catalog_sizethrough`.`product_id`)
WHERE (`catalog_products`.`deleted` = 0
AND `catalog_products`.`in_stock` = 1
AND `catalog_products_color`.`color_id` = 1
AND `catalog_products_category`.`categories_id` = 183
AND `catalog_sizethrough`.`size_id` IN (262)
AND `catalog_sizethrough`.`stock` = 1)
ORDER BY `catalog_products`.`title` ASC
LIMIT 48
Я пробовал так много вещейчтобы это исправить, но я не могу это исправить, мне нужно улучшить скорость загрузки моей страницы, но поскольку запрос занимает больше времени, это не так хорошо для пользователя.Я использовал загрузку Eager, поэтому улучшение уже не поможет, если у вас нет дополнений.
Код
Сериализатор
class ProductsListSerializer(serializers.ModelSerializer):
images = ImagesSerializer(many=True, source='get_first_two_images')
related_color = serializers.SerializerMethodField()
def get_related_color(self, obj):
return obj.related_color.count()
class Meta:
fields = (
'id',
'sku',
"title",
"old_price",
"price",
"sale",
"images",
"original_categories",
"related_color",
"original_conv_color",
"original_sizes",
)
model = Products
@staticmethod
def setup_eager_loading(queryset):
queryset = queryset.only('id', 'sku', 'title', 'old_price', 'price', 'sale', 'original_categories', 'original_conv_color', 'original_sizes').prefetch_related('images', 'related_color')
return queryset
Просмотр
class ProductsViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Products.objects.all()
permission_classes = [DjangoModelPermissionsOrAnonReadOnly]
filter_backends = (filters.SearchFilter, DjangoFilterBackend, filters.OrderingFilter, CustomFilter, SizeFilter)
filter_fields = ('slug', 'code', 'sku', 'color', 'attributes', 'category', 'original_color')
min_max_fields = ('price', 'sale')
search_fields = ('title', 'original_color', 'original_categories', 'original_conv_color', 'original_sizes')
ordering_fields = ('sale', 'price', 'created_at')
pagination_class = StandardResultsSetPagination
def get_queryset(self):
if self.action == 'list':
queryset = self.get_serializer_class().setup_eager_loading(self.queryset.filter(deleted=0,in_stock=1))
return queryset
return self.queryset
def get_serializer_class(self):
if self.action == 'list':
return ProductsListSerializer
if self.action == 'retrieve':
return ProductsSerializer
return ProductsSerializer