【问题标题】:Is there a better way to combine two queries other than using UNION? [closed]除了使用 UNION 之外,还有更好的方法来组合两个查询吗? [关闭]
【发布时间】:2021-08-15 09:20:31
【问题描述】:

我有两个相同的查询。我有一个案例,我想获取与集合相关的所有订单。我可以考虑使用 UNION,但它太慢了。

查询 1: 在这里,我尝试查询类型为 2 的订单,这意味着 ref_id 引用了一个变体。

orders -> order_items -> variants -> products -> lines -> collections

SELECT
    `orders`.*
FROM
    `orders`
    LEFT JOIN `order_items` ON `orders`.`id` = `order_items`.`order_id`
    LEFT JOIN `variants` ON `order_items`.`ref_id` = `variants`.`id`
    LEFT JOIN `line_products` ON `variants`.`parent_id` = `line_products`.`product_id`
        AND `order_items`.`type` = 2
    LEFT JOIN `collection_line` ON `line_products`.`line_id` = `collection_line`.`line_id`
WHERE
    `collection_line`.`collection_id` = 55;

查询 2: 在这里,我尝试查询项目类型为 1 的订单,这意味着 ref_id 正在引用产品。

订单 -> order_items -> 产品 -> 行 -> 集合

 SELECT
        `orders`.*
    FROM
        `orders`
        LEFT JOIN `order_items` ON `orders`.`id` = `order_items`.`order_id`
        LEFT JOIN `line_products` ON `order_items`.`ref_id` = `line_products`.`product_id`
            AND `order_items`.`type` = 1
        LEFT JOIN `collection_line` ON `line_products`.`line_id` = `collection_line`.`line_id`
    WHERE
        `collection_line`.`collection_id` = 55;

有没有办法可以组合和优化这两个查询?

【问题讨论】:

  • order_items.type IN (2,1)
  • 将一列用于两个外键是糟糕的设计:使用单独的列。
  • 您的最终连接是内部连接
  • 1) 慢有多慢? 2) 你能否通过运行SHOW CREATE TABLE table_name 来更新你的问题与所有表定义。 3)每个表有多少(估计的)数据行? 4) 它已经被提及,但是当你做 WHERE collection_line.collection_id=55; 时,LEFT JOIN collection_line .. 已经被转向 INNER JOIN
  • "combine" & "optimize" 没有特别的含义。 minimal reproducible example PS 了解子查询。 PS LEFT JOIN 返回由 NULL 扩展的 INNER JOIN 行 UNION ALL 不匹配的左表行。作为 OUTER JOIN 的一部分,始终知道您想要什么 INNER JOIN。在 LEFT JOIN 之后,需要右 [sic] 表列不为 NULL 的 WHERE、INNER JOIN 或 HAVING 删除任何引入了 NULL 的行,即只留下 INNER JOIN 行,即“将 OUTER JOIN 转换为 INNER JOIN”。你有那个。

标签: mysql sql join left-join


【解决方案1】:

你可以试试这个查询。

SELECT
    `orders`.*
FROM
    `orders`
    LEFT JOIN `order_items` ON `orders`.`id` = `order_items`.`order_id`
    LEFT JOIN `variants` ON `order_items`.`ref_id` = `variants`.`id`
    LEFT JOIN `line_products` ON `variants`.`parent_id` = `line_products`.`product_id`
        AND `order_items`.`type` IN ('1', '2')
    LEFT JOIN `collection_line` ON `line_products`.`line_id` = `collection_line`.`line_id`
WHERE
    `collection_line`.`collection_id` = 55;

使用IN

【讨论】:

  • 如果 order_items.type 为 1,则使用此查询只会查询变体表,而预期的结果是查询产品表。
【解决方案2】:

collection_line 听起来像是一个多对多映射表。如果是这样,请遵循此处的索引建议:http://mysql.rjweb.org/doc.php/index_cookbook_mysql#many_to_many_mapping_table 特别是,需要(collection_id, line_id) 上的复合索引。 line_products 也是如此。

p 需要(line_id, product_id)
i: (ref_id, type, order_id)

LEFT 可能是不必要的;看看没有它是否会得到相同的结果。

【讨论】:

    【解决方案3】:

    这适用于单个订单并进行双左连接。一个用于变体,第二个在默认行产品/集合上。您让 WHERE 子句的每个实例都包含“collection_id = 55”,这会将左连接更改为内部连接以满足需求。

    因此,对于一个根级订单表,两个左连接可以同时进行。唯一要添加的是“WHERE”子句。所以,无论是 NOT null 的条件,它应该是一个或另一个。

    select
          o.*
       from
          ( SELECT DISTINCT 
                  oi.order_id
               FROM
                  order_items oi
                     LEFT JOIN variants v
                        ON oi.ref_id = v.id
                        AND oi.type = 2
                        LEFT JOIN line_products lp
                            ON v.parent_id = lp.product_id
                            LEFT JOIN collection_line cl 
                                ON lp.line_id = cl.line_id
                                AND cl.collection_id = 55;
        
                     LEFT JOIN line_products lp2
                        ON oi2.ref_id = lp2.product_id
                        AND oi2.type = 1
                        LEFT JOIN collection_line cl2
                            ON lp2.line_id = cl2.line_id
                            AND cl2.collection_id = 55
               where
                      oi.type in ( 1,  2 )
                  AND (    cl.collection_id = 55
                       OR  cl2.collection_id = 55 )) PQ
          JOIN Orders o
             on PQ.order_id = o.id
    

    通过 OR,它不需要双方,但只要其中一个是合格的,订单就应该返回。因为连接可能会为同一订单创建多个退货,并且您没有拉状态。然后将这些唯一 ID 加入到订单表中

    【讨论】:

      猜你喜欢
      • 2011-08-28
      • 1970-01-01
      • 1970-01-01
      • 2015-12-08
      • 1970-01-01
      • 2018-08-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多