当WHERE中有变量时,Mysql查询不能使用索引

时间:2013-02-22 20:26:39

标签: mysql

我有这张桌子:

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

和这个查询:

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 =@sitio
        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)

我在解释中有这个

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  

但如果我不使用@sitio变量(但使用@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)

我明白了:

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  

任何想法为什么Mysql不使用@sitio变量的索引,但它与@fechaini和@fechafin一起使用?

谢谢!

1 个答案:

答案 0 :(得分:13)

最可能的解释是列nodo是字符数据类型,character_set_connection与为列指定的字符集不匹配。

如果使用latin1 characterset定义列,请尝试:

WHERE nodo = CONVERT(@sitio USING latin1)

作为演示,使用utf8,explain输出显示没有可用的索引:

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

但是对于latin1,解释输出显示索引可用(并且已使用):

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