Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/60.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql-优化-多组连接;使用have连接_Mysql_Optimization_Group Concat_Having - Fatal编程技术网

Mysql-优化-多组连接;使用have连接

Mysql-优化-多组连接;使用have连接,mysql,optimization,group-concat,having,Mysql,Optimization,Group Concat,Having,我已经看过类似的mysql优化线程组,但没有一个与我的问题相关,我的mysql知识也被这一个扩展了 我的任务是提高脚本的速度,其中包含一个非常繁重的Mysql查询 该查询使用GROUP_CONCAT创建一个颜色、标签和尺寸列表,所有这些都与特定产品相关。然后,它使用HAVING/FIND_IN_SET来过滤这些连接的列表,以查找由用户控件设置的属性并显示结果 在下面的示例中,它查找产品标签=1、产品颜色=18、产品尺寸=17的所有产品。因此,这可能是一个蓝色的产品(颜色)在中等(大小)的男性(标

我已经看过类似的mysql优化线程组,但没有一个与我的问题相关,我的mysql知识也被这一个扩展了

我的任务是提高脚本的速度,其中包含一个非常繁重的Mysql查询

该查询使用GROUP_CONCAT创建一个颜色、标签和尺寸列表,所有这些都与特定产品相关。然后,它使用HAVING/FIND_IN_SET来过滤这些连接的列表,以查找由用户控件设置的属性并显示结果

在下面的示例中,它查找产品标签=1、产品颜色=18、产品尺寸=17的所有产品。因此,这可能是一个蓝色的产品(颜色)在中等(大小)的男性(标签)

shop_products表包含大约3500行,因此不是特别大,但下面的表执行起来大约需要30秒。对于1个或2个联接,它可以正常工作,但是添加第三个联接只会使其失效

选择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
  • 获取该产品id可用的所有标签/颜色/尺寸组合的列表
  • 我想让你成为一个SQLFiddle,但是这个网站现在似乎已经坏了。尝试以下方法:

    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