2013-02-22 15 views
7

mam poniższej tabeli:Mysql dont't kwerendy używa indeksu, gdy istnieją zmienne GDZIE

CREATE TABLE `ClientesHora_copy` (
`dia` varchar(6) default NULL, 
`hora` varchar(2) default NULL, 
`sit` varchar(17) default NULL, 
`nodo` varchar(6) default NULL, 
`clientes` decimal(41,0) default NULL, 
`segundos` double default NULL, 
`llamadas` decimal(41,0) default NULL, 
`fecha` datetime default NULL, 
KEY `nodo_fecha` (`nodo`,`fecha`), 
KEY `nodo` (`nodo`) 
) ENGINE=MyISAM DEFAULT CHARSET=latin1 

i to zapytanie:

SET @sitio= 'ABA000'; 
SET @horaini='2013-02-12 15:18:00'; 
SET @horafin='2013-02-12 20:36:00';  
    EXPLAIN SELECT nodo,sit,clientes,segundos,llamadas,fecha,hora,@horaini AS horaini,@horafin AS horafin 
     FROM `ClientesHora_copy` 
     WHERE 
     nodo [email protected] 
     AND 
     fecha BETWEEN DATE_SUB(DATE_FORMAT(@horaini, "%Y-%m-%d %H:00:00"), INTERVAL 7 DAY) 
      AND DATE_SUB(DATE_FORMAT(@horafin, "%Y-%m-%d %H:00:00"), INTERVAL 7 DAY) 

mam to wytłumaczyć w

id select_type table    type possible_keys key  key_len ref  rows Extra   
------ ----------- ----------------- ------ ------------- ------ ------- ------ ------- ------------- 
1 SIMPLE  ClientesHora_copy ALL  (NULL)   (NULL) (NULL) (NULL) 2716460 Using where 

Ale jeśli nie używam zmiennej @sitio (ale używaj zmiennych @horaini, @horafin):

EXPLAIN SELECT nodo,sit,clientes,segundos,llamadas,fecha,hora,@horaini AS horaini,@horafin AS horafin 
     FROM `ClientesHora_copy` 
     WHERE 
     nodo ='ABA000' 
     AND 
     fecha BETWEEN DATE_SUB(DATE_FORMAT(@horaini, "%Y-%m-%d %H:00:00"), INTERVAL 7 DAY) 
      AND DATE_SUB(DATE_FORMAT(@horafin, "%Y-%m-%d %H:00:00"), INTERVAL 7 DAY) 

uzyskać to:

id select_type  table    type possible_keys key   key_len ref  rows Extra 
------ ----------- ----------------- ------ --------------- ---------- ------- ------ ------ ------------- 
1 SIMPLE   ClientesHora_copy range nodo_fecha,nodo nodo_fecha 18  (NULL)  1 Using where 

Każdy pomysł, dlaczego robi Mysql korzystać z indeksu ze zmienną @sitio ale robi z @fechaini i @fechafin?

Dzięki!

+2

Problem nie polega na braku "stałej" wartości (jak wskazuje wybrana odpowiedź). Dosyć łatwo można wykazać, że MySQL użyje indeksu "const" ref ze zmienną użytkownika. Problem polega na zestawie znaków; zmienna użytkownika jest prawdopodobnie innym zestawem znaków niż kolumna. Możemy użyć funkcji 'CONVERT()', która służy do konwersji pomiędzy różnymi zestawami znaków. – spencer7593

Odpowiedz

8

Najbardziej prawdopodobnym wyjaśnieniem jest to, że kolumna nodo jest typem danych znaku, a character_set_connection nie pasuje do zestawu znaków określonego dla kolumny.

Jeśli kolumna jest zdefiniowana z latin1 CharacterSet, spróbuj:

WHERE nodo = CONVERT(@sitio USING latin1) 

jako demonstracja, z utf8, tłumaczyć wyjście nie wykazuje indeks dostępne:

EXPLAIN SELECT t.* FROM mytable t WHERE t.foo = CONVERT(@foo USING utf8) 
                    ^^^^ 
id select_type table type possible_keys key key_len ref rows Extra   
-- ----------- ----- ---- ------------- ------ ------- ------ ---- ----------- 
1 SIMPLE  t  ALL (NULL)  (NULL) (NULL) (NULL) 3 Using where 

ale z latin1, wyjaśnij, że indeks pokazów wyjściowych jest dostępny (i jest używany):

EXPLAIN SELECT t.* FROM mytable t WHERE t.foo = CONVERT(@foo USING latin1) 
                    ^^^^^^  
id select_type table type possible_keys key key_len ref rows Extra   
-- ----------- ----- ---- ------------- ------ ------- ------ ---- ----------- 
1 SIMPLE  t  ref t_ix   t_ix 13  const  1 Using where 
+1

widocznie to był problem, zmieniłem deklarację zmiennej na SET @ sitio = CONVERT ("AA000" KORZYSTAJĄC z latin1); a zapytanie jest teraz NAPRAWDĘ szybkie. Dzięki! – Alejandro

+0

Dzięki, że rozwiązałam mój problem! –