Mysql查询优化在没有DISTINCT的情况下转换连接中的子查询

时间:2014-04-01 11:55:28

标签: mysql sql performance optimization

我有桌子:

CREATE TABLE IF NOT EXISTS `bk_cart_rule` (
  `id_cart_rule` int(10) unsigned NOT NULL DEFAULT '0',
  `cart_rule_restriction` tinyint(1) unsigned NOT NULL DEFAULT '0',
  KEY `id_cart_rule` (`id_cart_rule`),
  KEY `cart_rule_restriction` (`cart_rule_restriction`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE IF NOT EXISTS `bk_cart_rule_combination` (
  `id_cart_rule_1` int(10) unsigned NOT NULL,
  `id_cart_rule_2` int(10) unsigned NOT NULL,
  KEY `id_cart_rule_1` (`id_cart_rule_1`),
  KEY `id_cart_rule_2` (`id_cart_rule_2`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


CREATE TABLE IF NOT EXISTS `bk_cart_rule_lang` (
  `id_cart_rule` int(10) unsigned NOT NULL,
  `id_lang` int(10) unsigned NOT NULL,
  KEY `id_cart_rule` (`id_cart_rule`),
  KEY `id_lang` (`id_lang`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

一个查询:

SELECT SQL_NO_CACHE cr.*, crl.*, 1 as selected FROM bk_cart_rule cr 
LEFT JOIN bk_cart_rule_lang crl ON (cr.id_cart_rule = crl.id_cart_rule AND crl.id_lang = 2)

 WHERE cr.id_cart_rule != 375 AND
             (   cr.cart_rule_restriction = 0 OR 
                 cr.id_cart_rule IN ( 
                    SELECT IF(id_cart_rule_1 = 375, id_cart_rule_2, id_cart_rule_1) FROM bk_cart_rule_combination WHERE 375 = id_cart_rule_1 OR 375 = id_cart_rule_2 ) )

明显的优化是:

    SELECT SQL_NO_CACHE DISTINCT cr.*, crl.* 1 as selected FROM bk_cart_rule cr 
LEFT JOIN bk_cart_rule_lang crl ON (cr.id_cart_rule = crl.id_cart_rule AND crl.id_lang = 2) 
LEFT JOIN bk_cart_rule_combination crc ON (375 = crc.id_cart_rule_1 AND  cr.id_cart_rule = crc.id_cart_rule_2) OR (375 = crc.id_cart_rule_2  AND cr.id_cart_rule = crc.id_cart_rule_1)
WHERE  cr.id_cart_rule != 375 AND (cr.cart_rule_restriction = 0 OR NOT ISNULL(crc.id_cart_rule_1))

但是我怎么能摆脱DISTINCT(在bk_cart_rule_combination中我是双向组合:)

id_cart_rule_1 id_cart_rule_2
 375  776
 776  375

或者可能有更好的优化?

1 个答案:

答案 0 :(得分:1)

如果购物车规则的排序不重要,则添加约束,即第一个的id小于第二个的id。也就是说,按顺序将它们放在表格中。

遗憾的是,MySQL并不允许简单的check约束。相反,您必须以其他方式实现它。这是三个:

  • 实现插入/更新触发器以维护排序(并防止重复)。
  • 在应用程序端实现逻辑。
  • 在存储过程中包装所有数据修改并在存储过程中实现逻辑。

如果您不想解决所有问题(这可能有助于解决其他问题),您可以将select distinct替换为:

group by least(id_cart_rule_1,  id_cart_rule_2), greatest(id_cart_rule_1,  id_cart_rule_2)