2011-11-07 18 views
11

En los últimos días noté algo raro al optimizar mi consulta. Tengo una consulta simple que hace algo como:MYSQL - NO frente a var = falso

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

Noté MySQL no se utiliza ningún índice, por lo que empecé a hacer algunos experimentos. Accidentalmente reemplacé el "NO cancelado" con "cancelado = falso", y luego, Mysql comenzó a usar "cancelado" como índice. Después de eso he intentado usar el contrario:

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

mismo resultado! Cuando cambio eso a "cancelado = verdadero" el índice funciona nuevamente.

Mi pregunta es: ¿CÓMO PUEDE SER ?! ¿No está usando "NO" la manera "elegante"? De todos modos, no esperaba que hiciera ninguna diferencia.

Estoy usando InnoDB como el motor, pero obtengo el mismo resultado usando MyISAM. ¿Alguien puede aclarar las cosas? Gracias.

Editar: Estructura de la tabla

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 ; 
+0

¿qué versión usas? – neworld

+0

Versión del servidor: comunidad 5.1.43 – Phoenix

+0

Puedes publicar el DDL de la tabla. –

Respuesta

2

No estoy familiarizado con MySQL, pero pensar lógicamente, yo lo entiendo así:
Índice es como una guía telefónica, cuando está buscando "Cohen", puede obtenerlo de inmediato.
Pero si está buscando NOT "Cohen", tendrá que revisar cada entrada y comprobar si es diferente de "Cohen".
Por lo tanto, cuando busca valor específico, se lo acaba buscando. Y cuando usa NOT, busca cualquier otro valor que pueda caber dentro de tinyint(1) (ya que entiendo que no solo es 1 o 0, ¿verdad?).

+0

Creo que indican en la pregunta que 'WHERE cancelled 'no usa un índice también. Aunque no está claro a qué se refiere "El mismo resultado". –

+0

Bueno, creo que 'WHERE cancelled' es verdadero cuando el valor de 'cancelled' es 1, 2 o 3 ... Así que todavía no es ** predicado de ** valor específico –

+0

Ignorando el hecho de que la columna está declarada como 'tinyint (1)' la misma no especificidad sería el caso de 'WHERE cancelled = true'. –

3

A pesar de que se trata de utilizar un índice, el índice (aunque no lo crean) puede hacer su consulta más lento. Es un poco raro, pero está relacionado con la selectividad del índice. Generalmente se presenta en columnas de tipo booleano.

Se descrbed como:..

"¿Cómo son diferentes valores de un campo es un número de 0-1, aunque también se puede pensar en él como un porcentaje Un valor de 1 o 100%, significa que cada valor en el campo es único"

es importante tener en cuenta becouse:

"MySQL tiene un optimizador basado en costos. Esto significa que MySQL calcula los costos de diferentes formas de realizar una consulta y luego elige el más barato. Bueno, calcular los costos es una ciencia inexacta. Por lo tanto una estimación está tomada, y la estimación que está mal a veces "

llano simple:.

Si los datos que está buscando tiene más o menos el 20% del mismo valor (por ejemplo, , cancelado tiene 40% de su mesa) a continuación, es muy sencillo simplemente hacer un recorrido de tabla

EDIT:.

cuanto a su pregunta, explique te dice que MySQL está usin g un índice. Pero, puede que no sea bueno, la única forma de saber si su optimización es mejor es probar el rendimiento. Además, considere el costo de las operaciones INSERT, UPDATE y DELETE para mantener ese índice. Haga algunos perfiles con y sin el índice.

Tome un vistazo a esto:

+0

Gracias por su respuesta. Lo entiendo ahora. De todos modos, la pregunta aún permanece. ¿Cómo es que "NO var1" difiere de "var1 = falso"? – Phoenix

+0

Tienes razón, lo siento. Edité la respuesta. – santiagobasulto

1
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 

devoluciones

'2', '1' 

Y

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 

Devoluciones

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

por lo que parece que en el primer caso el true consigue echados a int y luego se usa en un predicado buscable, mientras que en el segundo caso el valor de la columna se convierte implícitamente. Los moldes implícitos generalmente hacen una condición inalcanzable.

Mirando el plan de explicar para su búsqueda con WHERE canceled = true da

+----+-------------+--------------+------+---------------+----------+---------+-------+------+-----------------------------+ 
| 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 | 
+----+-------------+--------------+------+---------------+----------+---------+-------+------+-----------------------------+ 

Mientras que para WHERE canceled se obtiene

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

Así que parece que ni siquiera puede considerar el índice en canceled como posible opción en este caso.

Cuestiones relacionadas