fredag 4 februari 2011

Varning för NOT-operatorn i MySQL med index

På senare tid har jag ibland använt NOT-operatorn ! i MySQL. T.ex. för att hämta alla registreringar som ännu ej processats:

SELECT * FROM registrations WHERE !processed;

Fältet processed i det här fallet är av typen TINYINT(1) (BOOLEAN).

Idag upptäckte jag till min stora förvåning att om jag lägger ett index på processed så har det ingen som helst effekt om jag använder ! eller NOT för att hitta raderna.

mysql> DESCRIBE SELECT * FROM registrations WHERE !processed;
+------+---------------+------+---------+------+--------+-------------+
| type | possible_keys | key  | key_len | ref  | rows   | Extra       |
+------+---------------+------+---------+------+--------+-------------+
| ALL  | NULL          | NULL | NULL    | NULL | 578614 | Using where |
+------+---------------+------+---------+------+--------+-------------+

Om jag däremot gör en helt vanlig jämförelse med 0 eller FALSE (som egentligen borde vara samma sak) så funkar det bra:

mysql> DESCRIBE SELECT * FROM registrations WHERE processed=FALSE;
+------+----------------+----------------+---------+-------+------+-------+
| type | possible_keys  | key            | key_len | ref   | rows | Extra |
+------+----------------+----------------+---------+-------+------+-------+
| ref  | processedindex | processedindex | 1       | const |    1 |       |
+------+----------------+----------------+---------+-------+------+-------+

I den här tabellen med nästan 600 000 rader tog queryn med ! 0.60 sekunder medan den som använde indexet tog 0.00.

Så kom ihåg! Använd inte "!", "NOT", "IS FALSE" eller liknande utan gör istället jämförelser med =. Även om de logiskt ger samma resultat.

Om någon vet varför det är på detta sätt så får ni gärna skriva en kommentar. Har sökt lite men inte hittat någon information om detta.

Inga kommentarer:

Skicka en kommentar