MariaDB使用修改后的索引减慢了左连接

时间:2016-12-28 17:42:43

标签: mariadb

我有一个旧的MySQL查询来查找始终正常工作的免费ID(0.0325秒)。但现在我已经改为MariaDB,而且速度非常慢(超过30秒)

SELECT 
   START AS codice
FROM (
    SELECT 
       codice +1 AS START 
    FROM  `clfoco` 
    WHERE 
       SUBSTRING(codice,9) BETWEEN '0000001' AND '9999999' AND codice LIKE '1201__%'
) AS a
LEFT JOIN (
    SELECT 
        codice
    FROM  `clfoco` 
    WHERE 
        SUBSTRING(codice,9) BETWEEN '0000001' AND '9999999' AND codice LIKE '1201__%'
) AS b ON a.start = b.codice
WHERE b.codice IS NULL 
LIMIT 1

" codice"是主要指标

旧数据库是MySQL 5.1.73 ,新数据库是MariaDB 5.5.52

我已经复制了表(导入/导出数据库和数据),删除并重新创建了索引,但新数据库中的查询总是很慢。

我已经阅读了更改索引(codice + 1)打破索引并强制MySQL扫描整个表的答案,但我不认为是这种情况,因为在旧MySQL数据库中查询速度很快。

有什么建议吗?

修改

CREATE TABLE IF NOT EXISTS `clfoco` (
  `codice` varchar(20) NOT NULL,
  `id_anagra` int(9) NOT NULL,
  `descri` varchar(100) DEFAULT NULL,
   ....
   ....
   ....
   PRIMARY KEY (`codice`),
  KEY `id_anagra` (`id_anagra`),
  FULLTEXT KEY `descri` (`descri`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

向Maria Db解释

| id|select_type|table |type    |possible_keys|key      |key_len|ref |rows  |Extra  
    ------------------------------------------------------------------------------
| 1 | SIMPLE    |clfoco|range   |PRIMARY      |PRIMARY  |62     |NULL|24549 |Using where; Using index  
| 1 | SIMPLE    |clfoco|index   |PRIMARY      |PRIMARY  |62     |NULL|25182 |Using where; Using index; Using join buffer (flat, BNL join)

用Mysql 5.1.73

解释
| id|select_type|table      |type   |possible_keys|key      |key_len|ref |rows  |Extra  
    ------------------------------------------------------------------------------
| 1 |PRIMARY    |<derived2> |ALL    |NULL         |NULL     |NULL   |NULL|24661  
| 1 |PRIMARY    |<derived3> |ALL    |NULL         |NULL     |NULL   |NULL|24661 |Using where; Not exists
| 3 | DERIVED   |clfoco     |index  |PRIMARY      |PRIMARY  |62     |NULL|25182 |Using where; Using index  
| 2 | DERIVED   |clfoco     |index  |PRIMARY      |PRIMARY  |62     |NULL|25182 |Using where; Using index; 

新编辑
在Rick James的建议之后我改变了查询。

SELECT  a.codice+1 AS START
    FROM  `clfoco` a
    WHERE codice LIKE '1201__%' 
      AND(substring(b.codice,9) between '0000001' and '9999999')
      AND NOT EXISTS (
                SELECT *
                FROM  `clfoco`
                WHERE codice LIKE '1201__%' 
                  AND (substring(b.codice,9) between '0000001' and '9999999')
                  AND codice = a.codice+1 )
    LIMIT 1;

MariaDB上的执行时间为0.0294秒

EXPLAIN EXTENDED:

id|select_type       |table |type |possible_keys|key    |key_len|ref |rows  |filtered|Extra
1 |PRIMARY           |a     |range|PRIMARY      |PRIMARY|62     |NULL|24549 |100.00  |Using where; Using index
2 |DEPENDENT SUBQUERY|clfoco|range|PRIMARY      |PRIMARY|62     |NULL|24549 |100.00  |Range checked for each record (index map: 0x1)

2 个答案:

答案 0 :(得分:0)

子选择似乎有点混淆,这总是很危险,因为即使它现在不会混淆优化器,它也可能在未来版本中(似乎已经发生)。我会写这个,没有子选择:

select a.codice+1 as codice
from clfoco a
left join clfoco b
    on b.codice=a.codice+1
    and (substring(b.codice,9) between '0000001' and '9999999')
    and b.codice like '1201__%'
where b.codice is null
and (substring(a.codice,9) between '0000001' and '9999999')
and a.codice like '1201__%'
limit 1;

这会使优化器更容易混淆吗?

从你添加的NOT EXISTS版本的解释中,看起来它正在使用like '1201__%'来索引依赖子查询,而不应该这样做。试试这个:

select a.codice+1 as codice
from clfoco a
left join clfoco b on b.codice=a.codice+1
where b.codice is null
and (substring(a.codice,9) between '0000001' and '9999999')
and a.codice like '1201__%'
and (substring(a.codice+1,9) between '0000001' and '9999999')
and a.codice+1 like '1201__%'
limit 1;

答案 1 :(得分:0)

SELECT  a.codice+1 AS START
    FROM  `clfoco` a
    WHERE codice LIKE '1201__%'
      AND NOT EXISTS (
                SELECT *
                FROM  `clfoco`
                WHERE codice LIKE '1201__%'
                  AND codice = a.codice+1 )
    LIMIT 1;

注意:

  • EXISTS可以更好地进行优化。 (但你的版本很老了。)
  • SUBSTRING妨碍了索引的使用。
  • SUBSTRING支票似乎没用。
  • codice需要VARCHAR,否则LIKE会有问题。

请提供SHOW CREATE TABLEEXPLAIN SELECT ...