首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >TINYINT列的MySQL索引:为什么检查'= 0‘和检查’是假‘之间有区别?

问TINYINT列的MySQL索引:为什么检查'= 0‘和检查’是假‘之间有区别?
EN

Stack Overflow用户
提问于 2020-05-18 20:47:19
回答 2查看 319关注 0票数 1

MySQL为查询提供了不同的执行计划,这取决于我是否检查索引的TINYINT字段‘为false’还是'= 0'。该表的名称为序号(意为“托运”),我希望MySQL使用的索引是shipmentslistrequest

SHOW CREATE ordini (为了简单起见,我省略了大多数列和索引):

代码语言:javascript
复制
CREATE TABLE `ordini` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `dataIns` datetime DEFAULT NULL,
  `hasLDV` tinyint(1) NOT NULL DEFAULT '0',
  `isAnnullato` tinyint(1) NOT NULL DEFAULT '0',
  `isEsportatoSAM` tinyint(1) DEFAULT '0',
  `id_azienda_aux` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `dataIns` (`dataIns`),
  KEY `id_azienda_aux` (`id_azienda_aux`),
  KEY `shipmentslistrequest` (`id_azienda_aux`,`isEsportatoSAM`,
                              `hasLDV`,`isAnnullato`,`dataIns`)
) ENGINE=InnoDB AUTO_INCREMENT=5007359 DEFAULT CHARSET=latin1

Query1

代码语言:javascript
复制
EXPLAIN  select  *
        from  ordini
        where  id_azienda_aux = 92
          and  isEsportatoSAM = 0
          and  isAnnullato = 0
          and  hasLDV = 1
          and  dataIns >= '2020-04-28'
          and  dataIns <  '2020-05-19';

id|select_type|table |type |possible_keys                              |key                 |key_len|ref|rows|Extra      |
--|-----------|------|-----|-------------------------------------------|--------------------|-------|---|----|-----------|
 1|SIMPLE     |ordini|range|dataIns,id_azienda_aux,shipmentslistrequest|shipmentslistrequest|17     |   | 138|Using where|

Query2 (更改: isEsportatoSAM为假):

代码语言:javascript
复制
EXPLAIN   select  *
        from  ordini
        where  id_azienda_aux = 92
          and  isEsportatoSAM is false
          and  isAnnullato = 0
          and  hasLDV = 1
          and  dataIns >= '2020-04-28'
          and  dataIns <  '2020-05-19';

id|select_type|table |type |possible_keys                              |key    |key_len|ref|rows  |Extra      |
--|-----------|------|-----|-------------------------------------------|-------|-------|---|------|-----------|
 1|SIMPLE     |ordini|range|dataIns,id_azienda_aux,shipmentslistrequest|dataIns|9      |   |205920|Using where|

Query3 (更改: isEsportatoSAM =0,isAnnullato为false):

代码语言:javascript
复制
EXPLAIN     select  *
        from  ordini
        where  id_azienda_aux = 92
          and  isEsportatoSAM = 0
          and  isAnnullato is false
          and  hasLDV = 1
          and  dataIns >= '2020-04-28'
          and  dataIns <  '2020-05-19';

id|select_type|table |type|possible_keys                              |key                 |key_len|ref              |rows|Extra      |
--|-----------|------|----|-------------------------------------------|--------------------|-------|-----------------|----|-----------|
 1|SIMPLE     |ordini|ref |dataIns,id_azienda_aux,shipmentslistrequest|shipmentslistrequest|7      |const,const,const| 206|Using where|

我猜是:

Query1将正确地利用托运人列表请求索引。

Query2不能在第一列之后使用它,因为我将isEsportatoSAM与false (,但为什么?)作比较。列允许空的事实是否有任何关联?),因此选择了不同的索引。

Query3将使用(并包括)第三列的索引,但由于“是错误的”比较而不再使用,这就是为什么ref列中的三个“const”,这就是为什么连接类型是'ref‘而不是' range’(它没有到达索引的日期范围部分)的原因。这个解释对吗?

有人能帮我解决这些问题吗?

PS: MySQL版本为5.5.56

PS2:从设计的角度来看,我知道在那些微小的列中允许空(我没有设计这个系统)是没有意义的。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-05-18 21:03:03

这只是猜测,但我怀疑这是因为IS boolean_value的目的是在测试它之前将任何数据类型转换为它的布尔值。当列是任何类型的IS FALSE时,查询优化器应该能够判断= 0与INT等价,然后使用索引,就像在第一个查询中一样,但显然MySQL没有实现该优化。

如果您想要更好的查询优化,MySQL通常不是选择的DB。

票数 1
EN

Stack Overflow用户

发布于 2020-05-18 21:07:00

isAnnullato = 0允许优化器使用索引。

isAnnullato is false要求查询查看每一行,并在布尔上下文中计算isAnnullato。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61878726

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档