【问题标题】:Optimize left join with several joins by OR?通过 OR 优化左连接与多个连接?
【发布时间】:2019-06-23 19:43:05
【问题描述】:

这是我的查询(已编辑)

SELECT
  en.name AS name,
  en.entity_id,
  COUNT(o.order_id) AS orders_qty,
  ROUND(SUM(o.total)) AS orders_sum,
  ROUND((SUM(o.total) / COUNT(o.order_id))) AS average_purchase,
  MIN(o.date_added) AS first_purchase,
  MAX(o.date_added) AS last_purchase,
  (SELECT COUNT(*) FROM oc_order WHERE order_status_id <> 0 AND customer_id = c.customer_id AND date_added <= NOW() - INTERVAL 3 MONTH) as periodicity
FROM oc_xile_entity en
  LEFT JOIN oc_xile_customer_to_entity c2en ON (c2en.entity_id = en.entity_id)
  LEFT JOIN oc_customer c ON (c2en.customer_id = c.customer_id)
LEFT JOIN oc_order o FORCE INDEX FOR JOIN (`unreg_customer_id`) ON ((o.customer_id = c2en.customer_id OR o.unreg_customer_id = c2en.customer_id) AND order_status_id <> 0)
  WHERE en.entity_id IS NOT NULL
GROUP BY en.entity_id
ORDER BY name ASC
LIMIT 0,700

...以及表格的相关部分...

CREATE TABLE oc_order 
( order_id int(11) NOT NULL PRIMARY KEY 
, customer_id int(11) NOT NULL DEFAULT '0'
, unreg_customer_id (unreg_customer_id)
, unreg_customer_id int(11) NOT NULL
, order_status_id int(11) NOT NULL DEFAULT '0'
, INDEX (customer_id)
);

CREATE TABLE oc_customer 
(customer_id int(11) NOT NULL PRIMARY KEY);

CREATE TABLE oc_xile_customer_to_entity 
(entity_id int(11) NOT NULL
,customer_id int(11) NOT NULL
,PRIMARY KEY (entity_id,customer_id)
,INDEX entity_id
);

当我查询它的表顺序 35506 行时需要超过 15 秒

最繁重的查询

LEFT JOIN oc_order o ON ((o.customer_id = c2en.customer_id OR o.unreg_customer_id = c2en.customer_id) AND order_status_id  0)

优化它的最佳方法是添加FORCE INDEX FOR JOIN (unreg_customer_id) 像这样LEFT JOIN oc_order o FORCE INDEX FOR JOIN (unreg_customer_id) ON ((o.customer_id = c2en.customer_id OR o.unreg_customer_id = c2en.customer_id) AND order_status_id &lt;&gt; 0) 它的增加速度和查询时间变成了3秒。但我认为它可以优化得更好。有谁能够帮我? 查询说明

【问题讨论】:

  • 左连接和分组我使用正确,没有这个我的查询返回错误的结果。你说优化没意义,为什么?
  • 所以只能优化LEFT JOIN oc_order o FORCE INDEX FOR JOIN (unreg_customer_id) ON ((o.customer_id = c2en.customer_id OR o.unreg_customer_id = c2en.customer_id) AND order_status_id &lt;&gt; 0)这个吗?由另一个查询(如联合)更改?有什么想法吗?
  • 我们显然共享非常不同的对与错概念。我建议您从一个小的样本数据集、期望的结果以及后者与前者的关系的简要说明重新开始。之后,我们可以谈论优化。为此,请参阅:Why should I provide an MCVE for what seems to me to be a very simple SQL query?
  • 对不起,我发布的不是完整的查询 = 我正在编辑它
  • 如果删除相关子查询,性能会怎样? - 我仍然不明白为什么这些是外连接而不是内连接

标签: mysql optimization left-join


【解决方案1】:

呃?该查询对LEFT JOINs 没有任何作用。但是,优化器可能太笨了,无法丢弃它们并获得等效的查询:

SELECT  en.name AS name , en.entity_id
    FROM  oc_xile_entity en
    WHERE  en.entity_id IS NOT NULL
    GROUP BY  en.entity_id
    ORDER BY  name ASC
    LIMIT  0 , 700

那么很可能是“不正确”,因为您选择了name,但没有按它进行分组。如果有多个names 与一个entity_id 相关联,那么应该显示哪个 name

请描述您想要实现的目标,并提供SHOW CREATE TABLE oc_xile_entity

【讨论】:

    猜你喜欢
    • 2021-06-08
    • 2011-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-05
    • 1970-01-01
    • 1970-01-01
    • 2011-01-06
    相关资源
    最近更新 更多