【发布时间】:2019-05-24 20:51:53
【问题描述】:
我一直在努力解决一个问题,我相信每个人在某些时候都会遇到。我现在有一个包含 150k 产品的小型数据库。 (在我写这篇文章时增加。)
我正在将 DRF 用于 api,并且一直在努力解决我拥有很多产品的类别性能。
I.E 我有一个名为“连衣裙”的类别,其中包含 34633 产品。
我的数据库的设计方式是我在它下面有几个关系。
产品有类别、属性、颜色、尺寸、相关产品M2M
查询
计数查询
809.83ms
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.52ms
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
正如您所见,查询的时间非常长,但这是我应用过滤器时棘手的部分,即我选择颜色过滤器并且尺寸时间开始减少。
应用过滤器的查询
计数查询
264.63ms
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.43ms
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
【问题讨论】:
标签: mysql django database django-rest-framework relational-database