2011-11-07 2 views
11

Ces derniers jours, j'ai remarqué quelque chose de bizarre optimisant ma requête. J'ai une requête simple qui fait quelque chose comme:MYSQL - NOT vs var = false

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

j'ai remarqué MySQL n'utilisait un indice, donc je commencé à faire quelques expériences. Accidentellement, j'ai remplacé le "NON annulé" par "cancelé = faux", puis, Mysql a commencé à utiliser "cancelé" comme index. Après que j'essayé d'utiliser le contraire:

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

Même résultat! Quand je change cela en "cancelled = true", l'index fonctionne à nouveau.

Ma question est: COMMENT VENIR ?! N'utilise pas "NON" la manière "élégante"? De toute façon, je ne m'attendais pas à ce que cela fasse une différence.

J'utilise InnoDB comme moteur, mais j'obtiens le même résultat en utilisant MyISAM. Quelqu'un peut-il clarifier les choses? Merci.

Edit: Structure de la table

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

quelle version utilisez-vous? – neworld

+0

Version du serveur: 5.1.43-community – Phoenix

+0

Pouvez-vous poster le DDL de la table. –

Répondre

2

Je ne connais pas Mysql, mais la pensée logique, je comprends comme ceci:
Index est comme un téléphone, lorsque vous cherchez "Cohen", vous pouvez l'obtenir tout de suite.
Mais si vous cherchez PAS "Cohen", vous devrez parcourir chaque entrée, et vérifiez si elle est différente de "Cohen".
Donc, quand vous cherchez valeur spécifique, il semble juste pour cela. Et lorsque vous utilisez PAS, il cherche toute autre valeur qui peut entrer à l'intérieur tinyint(1) (comme je comprends c'est non seulement 1 ou 0, est-ce?).

+0

Je pense qu'ils indiquent dans la question que «WHERE canceled» n'utilise pas non plus un index. Bien que pas si clair ce que "même résultat" se réfère à. –

+0

Eh bien, je pense, 'WHERE cancel' est vrai lorsque la valeur' cancelled' est 1, 2 ou 3 ... Donc ce n'est toujours pas une ** valeur spécifique ** prédicat –

+0

En ignorant le fait que la colonne est déclarée comme 'tinyint (1)' la même non-spécificité serait le cas pour 'WHERE canceled = true'. –

3

Même si il utilise un indice, l'indice (croyez-le ou non) peut rendre votre requête plus lente. C'est un peu bizarre, mais c'est lié à la sélectivité de l'indice. Il est généralement présenté dans des colonnes de type booléen.

Il est descrbed comme:..

« Comment les différentes valeurs d'un champ sont Il est un nombre de 0-1, mais vous pouvez aussi penser en pourcentage une valeur de 1 ou 100%, signifie que chaque valeur dans le champ est unique »

Il est important de considérer becouse:

"MySQL a un optimiseur basé sur les coûts. Cela signifie que MySQL calcule les coûts de différentes façons d'effectuer une requête, puis choisit le le moins cher. Eh bien, le calcul des coûts est une science inexacte. Ainsi, une estimation est prise, et l'estimation est parfois mal «

Plaine simple:.

Si les données que vous êtes à la recherche a plus ou moins 20% de la même valeur (par exemple , a annulé 40% de votre table) puis, il est facile de faire juste un scan de table

EDIT:.

en ce qui concerne votre question, Explain dit que MySQL est usin g un index. Mais, ce n'est peut-être pas bon, la seule façon de savoir si votre optimisation est meilleure est de tester les performances. En outre, considérez le costo des opérations INSERT, UPDATE et DELETE pour conserver cet index. Faire du profilage avec et sans l'index.

Jetez un oeil à ceci:

+0

Merci pour votre réponse. Je comprends cela maintenant. Peu importe, la question demeure. comment se fait-il que "NOT var1" diffère de "var1 = false"? – Phoenix

+0

Vous avez raison, désolé. J'ai édité la réponse. – 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 

Retours

'2', '1' 

Et

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 

Retours

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

Il semble donc que dans le premier cas, le true obtient àjeté 0 et ensuite utilisé dans un prédicat recherchable alors que dans le second cas, la valeur de la colonne est implicitement castée. Les distributions implicites rendent généralement une condition non-indiscutable.

En regardant le plan d'expliquer votre requête avec WHERE canceled = true donne

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

Alors que pour WHERE canceled vous

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

Il semble donc qu'il ne peut même considérer l'index sur canceled comme option possible dans ce cas.