简体   繁体   English

为什么这些查询会在MySQL 5.5和5.6中产生不同的结果?

[英]Why do these queries yield different results in MySQL 5.5 vs 5.6?

Can someone explain why these two queries (one using IN and one using EXISTS ) return different results in MySQL 5.6 but not in MySQL 5.5? 有人可以解释为什么这两个查询(一个使用IN和一个使用EXISTS )在MySQL 5.6中返回不同的结果但在MySQL 5.5中没有?

Using EXPLAIN , I can see different execution plans for each, but I need help understanding what's going on, and why would this IN logic be broken in 5.6 but not 5.5? 使用EXPLAIN ,我可以看到每个的不同执行计划,但我需要帮助了解正在发生的事情,为什么这个IN逻辑在5.6但不是5.5中被打破?

Fiddle illustrating the problem: http://sqlfiddle.com/#!9/da52b/95 小提琴说明了这个问题: http ://sqlfiddle.com/#!9 / da52b / 95

Members can have two addresses: a home address and a firm address. 会员可以有两个地址:家庭住址和公司地址。 The desired result is to provide a region X and get a list of all members with a mailing address in that region. 期望的结果是提供区域X并获得该区域中具有邮寄地址的所有成员的列表。 The mailing address is the firm address if it exists, otherwise it is the home address. 邮件地址是公司地址(如果存在),否则它是家庭住址。 Cities can belong to one or more regions. 城市可以属于一个或多个地区。

Simplified database structure and data: 简化的数据库结构和数据:

CREATE TABLE `city` (
  `c_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `c_name` varchar(255) NOT NULL DEFAULT '',
  PRIMARY KEY (`c_id`)
);

INSERT INTO `city`
VALUES
  ('1', 'Hillsdale'),
  ('2', 'Smallville'),
  ('3', 'Oakside'),
  ('4', 'Lakeview');

CREATE TABLE `city_region` (
  `cr_city` int(11) unsigned NOT NULL,
  `cr_region` int(11) NOT NULL,
  PRIMARY KEY (`cr_city`,`cr_region`)
);

INSERT INTO `city_region`
VALUES
  ('1', '3'),
  ('2', '1'),
  ('3', '1'),
  ('3', '2'),
  ('4', '1'),
  ('4', '3');

CREATE TABLE `firm_address` (
  `fa_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `fa_member` int(11) NOT NULL,
  `fa_city` int(11) NOT NULL,
  PRIMARY KEY (`fa_id`)
);

INSERT INTO `firm_address`
VALUES
  ('1', '1', '3'),
  ('2', '2', '2'),
  ('3', '3', '1'),
  ('4', '6', '2'),
  ('5', '7', '1');

CREATE TABLE `home_address` (
  `ha_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `ha_member` int(11) NOT NULL,
  `ha_city` int(11) NOT NULL,
  PRIMARY KEY (`ha_id`)
);

INSERT INTO `home_address`
VALUES
  ('1', '1', '2'),
  ('2', '2', '3'),
  ('3', '3', '1'),
  ('4', '4', '1'),
  ('5', '5', '2'),
  ('6', '6', '2');

CREATE TABLE `member` (
  `m_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `m_name` varchar(255) NOT NULL DEFAULT '',
  PRIMARY KEY (`m_id`)
);

INSERT INTO `member`
VALUES
  ('1', 'John'),
  ('2', 'Bob'),
  ('3', 'Dave'),
  ('4', 'Jane'),
  ('5', 'Mary'),
  ('6', 'Karen'),
  ('7', 'Christie');

CREATE TABLE `region` (
  `r_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `r_name` varchar(255) NOT NULL DEFAULT '',
  PRIMARY KEY (`r_id`)
);

INSERT INTO `region`
VALUES
  ('1', 'Central'),
  ('2', 'Lake District'),
  ('3', 'Westside');

Query 1 (wrong, missing a member): 查询1(错误,缺少成员):

SELECT * FROM member

LEFT OUTER JOIN home_address ON m_id = ha_member
LEFT OUTER JOIN city home_city ON ha_city = home_city.c_id
LEFT OUTER JOIN firm_address ON m_id = fa_member
LEFT OUTER JOIN city firm_city ON fa_city = firm_city.c_id

WHERE 1 IN (
    SELECT r_id
    FROM region
    INNER JOIN city_region ON r_id = cr_region
    WHERE cr_city = IF(fa_city IS NULL, ha_city, fa_city)
)

Query 2 (returning the correct results): 查询2(返回正确的结果):

SELECT * FROM member

LEFT OUTER JOIN home_address ON m_id = ha_member
LEFT OUTER JOIN city home_city ON ha_city = home_city.c_id
LEFT OUTER JOIN firm_address ON m_id = fa_member
LEFT OUTER JOIN city firm_city ON fa_city = firm_city.c_id

WHERE EXISTS (
    SELECT r_id
    FROM region
    INNER JOIN city_region ON r_id = cr_region
    WHERE cr_city = IF(fa_city IS NULL, ha_city, fa_city)
    AND r_id = 1
)

Any help understanding this inconsistency would be appreciated. 任何帮助理解这种不一致将不胜感激。

Thank you. 谢谢。

I spent some time looking at this today, and it appears to be a bug in MySQL 5.6. 今天我花了一些时间看这个,它似乎是MySQL 5.6中的一个错误。 (I also tested MySQL 5.6.15 and got the same result.) (我也测试了MySQL 5.6.15并得到了相同的结果。)

MySQL 5.6 uses some new optimizations in executing this query, but they do not seem to be responsible for the difference, as it does not help to set eg: MySQL 5.6在执行此查询时使用了一些新的优化,但它们似乎并没有对差异负责,因为它没有帮助设置例如:

set session optimizer_switch="block_nested_loop=off";

Using IFNULL(fa_city, ha_city) instead of IF(fa_city IS NULL, ha_city, fa_city) does yield a correct result, so the bug appears to be somewhere in the processing of IF() . 使用IFNULL(fa_city, ha_city)而不是IF(fa_city IS NULL, ha_city, fa_city)确实产生了正确的结果,因此bug似乎在处理IF()某个地方。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM