TINYINT列上的MySQL索引:为什么检查“=0”和检查“is false”之间有区别?
MySQL为查询提供了不同的执行计划,这取决于我是否检查索引的TINYINT字段“为false”或“=0”。表的名称是ordini,意思是“发货”,我希望MySQL使用的索引是shipmentslistrequest 为简单起见,SHOW CREATE ordini I省略了大多数列和索引:TINYINT列上的MySQL索引:为什么检查“=0”和检查“is false”之间有区别?,mysql,performance,indexing,boolean,tinyint,Mysql,Performance,Indexing,Boolean,Tinyint,MySQL为查询提供了不同的执行计划,这取决于我是否检查索引的TINYINT字段“为false”或“=0”。表的名称是ordini,意思是“发货”,我希望MySQL使用的索引是shipmentslistrequest 为简单起见,SHOW CREATE ordini I省略了大多数列和索引: CREATE TABLE `ordini` ( `id` int(11) NOT NULL AUTO_INCREMENT, `dataIns` datetime DEFAULT NULL, `h
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
问题1:
查询2更改:iSportAtom为false:
查询3更改:IsSportAtoSam=0,isAnnullato为false:
我的猜测是:
查询1将正确利用shipmentslistrequest索引
Query2无法在第一列之外使用它,因为我将IseSortatosam与false进行比较,但为什么?。列允许空值这一事实是否有任何相关性?并因此选择不同的索引
Query3将使用第三列之前(包括第三列)的索引,但不会进一步使用,因为“is false”比较,这就是为什么ref列中有三个“const”,这就是为什么连接类型是“ref”而不是“range”,它不会到达索引的日期范围部分。这个解释正确吗
有谁能帮我解决这些问题吗
PS:MySQL版本是5.5.56
PS2:从设计的角度来看,我知道在我没有设计这个系统的那些小列中允许空值是没有意义的。这只是一个猜测,但我怀疑这是因为is boolean\u值是为了在测试任何数据类型之前将其转换为boolean值而设计的。当列为任何类型的INT时,查询优化器应该能够判断IS FALSE等于=0,然后在第一个查询中使用索引,但显然MySQL没有实现该优化 如果您想进行出色的查询优化,MySQL通常不是首选数据库。isAnnullato=0允许优化器使用索引
isAnnullato为false要求查询查看每一行并在布尔上下文中计算isAnnullato。我无法重现该问题,但我没有任何数据。两个建议1.5.5已经很老了;升级2下拉键id_azienda_aux;这是不必要的,因为综合指数。我见过这样的情况,优化器使用较小的索引,尽管较大的索引更好。@RickJames我将删除冗余索引,谢谢。还有一个问题:在问题1的WHERE中添加一个新的比较应该不是问题,对吧?我这样问是因为手册中说,如果列不构成索引最左边的前缀,MySQL就不能使用索引来执行查找,我发现这一措辞令人困惑。在我的查询中添加一个新列会使它不是索引最左边的前缀,但索引仍然会被使用,对吗?因此,最好说查询必须包含索引中列的最左侧前缀,对吗?这些示例可能有助于澄清最左侧前缀混淆:我无法在5.5或更高版本上重现这种情况。我希望IS FALSE等于=0,但我没有证据或反驳。FALSE表示为0,所以我对这个答案表示怀疑。另一方面,TRUE是任何非零值,所以这将是一种不同的情况。
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|
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|
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|