Mysql-优化-多组连接;使用have连接
我已经看过类似的mysql优化线程组,但没有一个与我的问题相关,我的mysql知识也被这一个扩展了 我的任务是提高脚本的速度,其中包含一个非常繁重的Mysql查询 该查询使用GROUP_CONCAT创建一个颜色、标签和尺寸列表,所有这些都与特定产品相关。然后,它使用HAVING/FIND_IN_SET来过滤这些连接的列表,以查找由用户控件设置的属性并显示结果 在下面的示例中,它查找产品标签=1、产品颜色=18、产品尺寸=17的所有产品。因此,这可能是一个蓝色的产品(颜色)在中等(大小)的男性(标签) shop_products表包含大约3500行,因此不是特别大,但下面的表执行起来大约需要30秒。对于1个或2个联接,它可以正常工作,但是添加第三个联接只会使其失效Mysql-优化-多组连接;使用have连接,mysql,optimization,group-concat,having,Mysql,Optimization,Group Concat,Having,我已经看过类似的mysql优化线程组,但没有一个与我的问题相关,我的mysql知识也被这一个扩展了 我的任务是提高脚本的速度,其中包含一个非常繁重的Mysql查询 该查询使用GROUP_CONCAT创建一个颜色、标签和尺寸列表,所有这些都与特定产品相关。然后,它使用HAVING/FIND_IN_SET来过滤这些连接的列表,以查找由用户控件设置的属性并显示结果 在下面的示例中,它查找产品标签=1、产品颜色=18、产品尺寸=17的所有产品。因此,这可能是一个蓝色的产品(颜色)在中等(大小)的男性(标
选择shop\u products.id、shop\u products.name、shop\u products.default\u image\u id,
作为产品颜色的组CONCAT(不同的车间产品颜色。颜色id),
组_CONCAT(不同的车间_产品_to_tag.tag_id)作为产品标签,
产品尺寸分组(不同的店铺、产品、颜色、尺寸、标签、id)
来自shop_产品
左连接店铺商品到店铺商品上的商品颜色。id=店铺商品到商品颜色。商品id
左连接店铺商品到店铺商品上的标签。id=店铺商品到标签。商品id
左连接店铺商品颜色到店铺商品上的尺码。id=店铺商品颜色到尺码。产品id
其中shop\u products.category\u id='50'
按店铺编号分组
具有((在集合中查找集合(1,产品标签)>0)
和(在集合中查找(18,产品颜色)>0)
和(在集合中查找集合(17,产品大小>0))
按店铺\产品订购。名称ASC
限制0,30
我希望有人能提出一种更好的方法来构造这个查询,而不必重新构造数据库(如果没有数周的数据迁移和脚本更改,这在目前还不是一个选项)?或任何关于优化的一般建议。使用explain当前返回以下内容(正如您可以看到的那样,索引到处都是!)
重写查询以使用
WHERE
而不是have
。因为当MySQL对行执行搜索时,应用了,并且可以使用索引<选择行后应用代码>具有
,以筛选已选择的结果<代码>按设计拥有不能使用索引。例如,您可以这样做:
选择p.id、p.name、p.default\u image\u id、,
作为产品颜色的组CONCAT(不同的pc.colour\U id),
组CONCAT(不同的pt.tag\u id)作为产品标签,
按产品尺寸分组(不同的ps.tag\U id)
来自shop_products p
加入p.id=pc\U test.product\U id和pc\U test.colour\U id=18上的车间产品到颜色pc\U测试
在p.id=pt\u test.product\u id和pt\u test.tag\u id=1上加入车间产品标签pt\u test
加入车间产品颜色尺寸ps测试p.id=ps测试产品id和ps测试标签id=17
在p.id=pc.product\U id上加入商店\U product\U至\U COLORS pc
加入车间产品,在p.id=pt.product\U id上标记pt
加入店铺\u产品\u颜色\u至\u尺寸p.id=ps.product\u id
其中p.category_id='50'
按p.id分组
按p.name ASC订购
更新
我们将每个表合并两次。首先检查它是否包含一些值(来自
FIND\u IN\u SET
的条件)。第二次联接将为
组_CONCAT
生成数据,以从表中选择所有产品值
更新2
正如@Matt Raines所评论的,如果我们不需要用GROUP\u CONCAT
列出产品值,查询就会变得更简单:
选择p.id、p.name、p.default\u image\u id
来自shop_products p
在p.id=pc.product\U id上加入商店\U product\U至\U COLORS pc
加入车间产品,在p.id=pt.product\U id上标记pt
加入店铺\u产品\u颜色\u至\u尺寸p.id=ps.product\u id
其中p.category_id='50'
和(pc.colour_id=18,pt.tag_id=1,ps.tag_id=17)
按p.id分组
按p.name ASC订购
这将选择具有三个过滤属性的所有产品。我想如果我理解这个问题,您需要做的是:
商店\u product.id
SELECT shop_products.id, shop_products.name, shop_products.default_image_id,
GROUP_CONCAT( DISTINCT shop_product_to_colours.colour_id ) AS product_colours,
GROUP_CONCAT( DISTINCT shop_products_to_tag.tag_id ) AS product_tags,
GROUP_CONCAT( DISTINCT shop_product_colour_to_sizes.tag_id ) AS product_sizes
FROM
shop_products INNER JOIN
(SELECT shop_products.id id,
FROM
shop_products
LEFT JOIN shop_product_to_colours ON shop_products.id = shop_product_to_colours.product_id
LEFT JOIN shop_products_to_tag ON shop_products.id = shop_products_to_tag.product_id
LEFT JOIN shop_product_colour_to_sizes ON shop_products.id = shop_product_colour_to_sizes.product_id
WHERE
shop_products.category_id = '50'
shop_products_to_tag.tag_id=1
shop_product_to_colours.colour_id=18
shop_product_colour_to_sizes.tag_id=17
) matches ON shop_products.id = matches.id
LEFT JOIN shop_product_to_colours ON shop_products.id = shop_product_to_colours.product_id
LEFT JOIN shop_products_to_tag ON shop_products.id = shop_products_to_tag.product_id
LEFT JOIN shop_product_colour_to_sizes ON shop_products.id = shop_product_colour_to_sizes.product_id
GROUP BY shop_products.id
ORDER BY shop_products.name ASC
LIMIT 0 , 30;
第一种方法的问题是,它需要数据库创建每个产品的每个组合,然后进行筛选。在我的示例中,我首先过滤产品id,然后生成组合
我的查询未经测试,因为我手头没有MySQL环境,SqlFIDLE也已关闭,但它应该能让您了解情况。首先,我为您的查询添加了别名以缩短可读性
SP = Shop_Products
PC = Shop_Products_To_Colours
PT = Shop_Products_To_Tag
PS = Shop_Products_To_Sizes
其次,你的have应该是一个WHERE,因为你明确地在寻找某样东西。在返回结果后,不需要尝试查询整个系统来抛出记录。第三,您有左连接,但当适用于WHERE或have且不允许NULL时,它会强制进行连接(这两个部分都是必需的)。最后,WHERE子句在您要查找的ID周围有引号,但无论如何这可能是整数。删除引号
现在,关于索引和优化。为了帮助处理条件、分组和联接,我将使用以下复合索引(多个字段),而不是仅使用单个列作为索引的表
table index
Shop_Products ( category_id, id, name )
Shop_Products_To_Colours ( product_id, colour_id )
Shop_Products_To_Tag ( product_id, tag_id )
Shop_Products_To_Sizes ( product_id, tag_id )
GROUP BY
SP.name,
SP.id
ORDER BY
SP.name ASC,
SP.ID
修订查询
SELECT
SP.id,
SP.name,
SP.default_image_id,
GROUP_CONCAT( DISTINCT PC.colour_id ) AS product_colours,
GROUP_CONCAT( DISTINCT PT.tag_id ) AS product_tags,
GROUP_CONCAT( DISTINCT PS.tag_id ) AS product_sizes
FROM
shop_products SP
JOIN shop_product_to_colours PC
ON SP.id = PC.product_id
AND PC.colour_id = 18
JOIN shop_products_to_tag PT
ON SP.id = PT.product_id
AND PT.tag_id = 1
JOIN shop_product_colour_to_sizes PS
ON SP.id = PS.product_id
AND PS.tag_id = 17
WHERE
SP.category_id = 50
GROUP BY
SP.id
ORDER BY
SP.name ASC
LIMIT
0 , 30
最后一点意见。由于您是按名称排序,但按ID分组,因此可能会导致最终排序延迟。但是,如果您将其更改为“按名称加ID分组”,您的ID仍将是唯一的,但您的店铺产品上的调整索引将是唯一的
table index
Shop_Products ( category_id, name, id )
w
GROUP BY
SP.name,
SP.id
ORDER BY
SP.name ASC,
SP.ID