如果将表定义为MyISAM或InnoDB,则SQL查询会以不同方式计算COUNT(*)

时间:2018-03-22 14:01:43

标签: mysql innodb myisam

我正在运行 MySQL 数据库。

我有以下脚本:

DROP TABLE IF EXISTS `org_apiinteg_assets`;
DROP TABLE IF EXISTS `assessmentinstances`;

CREATE TABLE `org_apiinteg_assets` (
  `id` varchar(20) NOT NULL default '0',
  `instance_id` varchar(20) default NULL,
  PRIMARY KEY  (`id`)
) ENGINE= MyISAM DEFAULT CHARSET=utf8 PACK_KEYS=1;

CREATE TABLE `assessmentinstances` (
  `id` varchar(20) NOT NULL default '0',
  `title` varchar(180) default NULL,
  PRIMARY KEY  (`id`)
) ENGINE= MyISAM DEFAULT CHARSET=utf8 PACK_KEYS=1;


INSERT INTO assessmentinstances(id, title) VALUES ('14026lvplotw6','One radio question survey');
INSERT INTO org_apiinteg_assets(id, instance_id) VALUES ('8kp9wgx43jflrgjfe','14026lvplotw6');

看起来像这样

assessmentinstances
+---------------+---------------------------+
|        id     |          title            |
+---------------+---------------------------+
| 14026lvplotw6 | One radio question survey |
+---------------+---------------------------+

org_apiinteg_assets
+-------------------+---------------+
|        id         |  instance_id  |
+-------------------+---------------+
| 8kp9wgx43jflrgjfe | 14026lvplotw6 |
+-------------------+---------------+

然后我有以下查询(我将其简化为最简单的失败查询)

SELECT ai.id, COUNT(*) AS `count` 
FROM assessmentinstances ai, org_apiinteg_assets a 
WHERE a.instance_id = ai.id 
AND ai.id = '14026lvplotw6'
AND a.id != '8kp9wgx43jflrgjfe';

当我运行查询时,我得到了这个

null, 0

直到现在,一切都很好。现在,这是我的问题,当我使用ENGINE=InnoDB而不是ENGINE=MyISAM重新创建两个表并再次运行相同的查询时,我得到了这个:

'14026lvplotw6','0'

所以有两件事令我困惑:

  • 为什么我得不到同样的结果?
  • COUNT(*)如何在第二种情况下返回0时实际返回行的值,因此应为1?

我迷了,如果有人能向我解释这种行为,我会很感激。

修改: 有趣的是,如果我在查询末尾添加GROUP BY ai.id,它在两种情况下都能正常工作并且不返回任何行。

2 个答案:

答案 0 :(得分:3)

这是因为您使用的聚合函数没有GROUP BY ..在这种情况下,非聚合列的结果是不可预测的..(通常显示查询期间遇到的第一个值)

尝试添加GROUP BY

SELECT ai.id, COUNT(*) AS `count` 
FROM assessmentinstances ai, org_apiinteg_assets a 
WHERE a.instance_id = ai.id 
AND a.id != '8kp9wgx43jflrgjfe'
AND ai.id = '14026lvplotw6' 
GROUP BY  ai.id;

请记住,在group by中未提及的列存在时使用聚合在SQL中已弃用,并且在大多数db和更新版本的mysql中不允许使用(从5.7开始)

答案 1 :(得分:1)

MyISAM的

EXPLAIN SELECT返回:Impossible WHERE noticed after reading const tables。所以MyISAM根本不处理任何数据。

对于InnoDB,有两行EXPLAIN结果:一行Using Index和一行Using where。因此,正在扫描InnoDB数据,并且它的位数滑入输出,因为没有为第一列指定聚合函数,而AFAIK没有指定在这种情况下应该发生什么。如果直接指定某个聚合函数,则if there are no matching rows, it will return NULL。因此,例如,SELECT min(ai.id), COUNT(*) ...将返回NULL, 0