简体   繁体   English

MYSQL - NOT vs var = false

[英]MYSQL - NOT vs var=false

In the last past days I noticed something weird optimizing my query. 在过去的几天里,我发现了一些奇怪的优化我的查询。 I have a simple query which does something like: 我有一个简单的查询,它具有以下特点:

   SELECT id,name,amount FROM reservations WHERE NOT canceled ORDER BY name ASC

I noticed mysql wasn't using any index, so I started doing some experiments. 我注意到mysql没有使用任何索引,所以我开始做一些实验。 Accidentally I replaced the "NOT canceled" with "canceled=false", and then, Mysql started using "canceled" as index. 无意中我将“NOT cancel”替换为“cancelled = false”,然后,Mysql开始使用“cancelled”作为索引。 After that I tried using the opposite: 之后我尝试使用相反的方法:

   SELECT ... FROM reservations WHERE canceled ORDER BY ...

Same result! 结果相同! When I change that to "canceled=true" the index works again. 当我将其更改为“cancelled = true”时,索引再次起作用。

My question is: HOW COME?! 我的问题是:怎么样?! Isn't using "NOT" the "elegant" way? 是不是使用“NOT”的“优雅”方式? Anyhow I didn't expect for it to make any difference. 无论如何,我没想到它会有任何不同。

I'm using InnoDB as the engine, but i get same result using MyISAM. 我使用InnoDB作为引擎,但我使用MyISAM获得相同的结果。 Can someone clarify things up? 有人能澄清一切吗? Thanks. 谢谢。

Edit: Table structure 编辑:表结构

CREATE TABLE `reservations` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `trip_code` varchar(10) DEFAULT NULL,
  `departure_date` date DEFAULT NULL,
  `amount` float DEFAULT NULL,
  `name` varchar(45) DEFAULT NULL,
  `canceled` tinyint(1) NOT NULL DEFAULT '0',
  `created_date` date NOT NULL,
  `creator_user` int(11) NOT NULL DEFAULT '1',
  `last_update_user` int(11) NOT NULL DEFAULT '1',
  PRIMARY KEY (`id`),
  KEY `trip_code` (`trip_code`),
  KEY `departure_date` (`departure_date`),
  KEY `created_date` (`created_date`),
  KEY `canceled` (`canceled`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=123181 ;

Even though it's using an index, the index (believe it or not) may make your query slower. 即使它正在使用索引,索引(信不信由你)可能会使您的查询变慢。 It's a little weird, but it's related to index selectivity. 这有点奇怪,但它与索引选择性有关。 It's generally presented in columns of type boolean. 它通常以boolean类型的列呈现。

It's descrbed like: 它的描述如下:

"How different values of a field are. It is a number from 0-1, although you can also think of it as a percentage. A value of 1, or 100%, means that each value in the field is unique" “字段的不同值是多少。它是0-1的数字,但您也可以将其视为百分比。值1或100%表示字段中的每个值都是唯一的”

It's important to consider becouse: 重要的是要考虑因为:

"MySQL has a cost-based optimizer. This means that MySQL calculates the costs of different ways of performing a query and then chooses the cheapest one. Well, calculating the costs is an inexact science. So an estimate is taken, and the estimate is wrong sometimes." “MySQL有一个基于成本的优化器。这意味着MySQL计算执行查询的不同方式的成本,然后选择最便宜的一个。那么,计算成本是一个不精确的科学。所以进行估计,估计是有时错了。“

Plain simple: 简单明了:

If the data you're looking has more or less 20% of the same value (for example, cancelled has 40% of your table) then, it's simple to just do a table scan. 如果您正在查找的数据具有或多或少20%的相同值(例如,取消了您的表的40%),则只需执行表扫描即可。

EDIT: 编辑:

Regarding your question, EXPLAIN tells you that MySQL is using an index. 关于你的问题,EXPLAIN告诉你MySQL正在使用索引。 But, it might not be good, the only way to note whether your optimization is better is to test performance. 但是,它可能不太好,注意优化是否更好的唯一方法是测试性能。 Also, consider the costo of INSERT, UPDATE and DELETE operations to keep that index. 另外,考虑INSERT,UPDATE和DELETE操作的costo以保持该索引。 Do some profiling with and without the index. 使用和不使用索引进行一些分析。

Take a look at this: 看看这个:

I am not familiar with MYSQL, but thinking logically, I understand it like this: 我不熟悉MYSQL,但从逻辑上思考,我理解如下:
Index is like a phone book, when you are searching for "Cohen", you can get it right away. 索引就像电话簿,当你搜索“科恩”时,你可以马上得到它。
But if you are looking for NOT "Cohen", you will have to run over every entry, and check if it's different from "Cohen". 但是,如果你正在寻找 “科恩”,你将不得不跑过每一个条目,并检查它是否与“科恩”不同。
So when you are looking for specific value , it looks just for it. 因此,当您寻找特定价值时 ,它看起来就是它。 And when you are using NOT , it looks for any other value that can fit inside tinyint(1) (as I understand it's not only 1 or 0 , is it?). 当你使用NOT时 ,它会寻找任何可以适合tinyint(1)其他值(据我所知它不仅仅是10 ,不是吗?)。

SELECT *
FROM 
(SELECT 1 AS C, 0 AS X UNION ALL
SELECT 2 AS C, 1 AS X UNION ALL
SELECT 3 AS C, 2 AS X ) T
WHERE X=true

Returns 返回

'2', '1'

And

SELECT *
FROM 
(SELECT 1 AS C, 0 AS X UNION ALL
SELECT 2 AS C, 1 AS X UNION ALL
SELECT 3 AS C, 2 AS X ) T
WHERE X

Returns 返回

'2', '1'
'3', '2'

So it seems that in the first case the true gets cast to int and then used in a seekable predicate whereas in the second case the column value is implicitly cast. 因此,在第一种情况下,似乎将trueint ,然后在可查找谓词中使用,而在第二种情况下,列值是隐式转换的。 Implicit casts generally make a condition unsargable. 隐式演员通常会使条件无法实现。

Looking at the explain plan for your query with WHERE canceled = true gives 使用WHERE canceled = true查看查询的解释计划

+----+-------------+--------------+------+---------------+----------+---------+-------+------+-----------------------------+
| id | select_type |    table     | type | possible_keys |   key    | key_len |  ref  | rows |            Extra            |
+----+-------------+--------------+------+---------------+----------+---------+-------+------+-----------------------------+
|  1 | SIMPLE      | reservations | ref  | canceled      | canceled |       1 | const |    1 | Using where; Using filesort |
+----+-------------+--------------+------+---------------+----------+---------+-------+------+-----------------------------+

Whereas for WHERE canceled you get 而对于WHERE canceled你得到

+----+-------------+--------------+------+---------------+-----+---------+-----+------+-----------------------------+
| id | select_type |    table     | type | possible_keys | key | key_len | ref | rows |            Extra            |
+----+-------------+--------------+------+---------------+-----+---------+-----+------+-----------------------------+
|  1 | SIMPLE      | reservations | ALL  |               |     |         |     |    2 | Using where; Using filesort |
+----+-------------+--------------+------+---------------+-----+---------+-----+------+-----------------------------+

So it appears that it can't even consider the index on canceled as a possible option in this case. 因此,在这种情况下,它似乎甚至不能将canceled的索引视为可能的选项。

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

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