Mysql没有使用正确的索引

时间:2018-04-06 19:32:05

标签: mysql sql indexing

我有一个生成SQL的框架。其中一个查询是使用我的索引" A"并在7秒内返回结果。我看到我可以优化这个并且我创建了一个索引" B"。

现在,如果我运行"解释我的查询",它仍然使用我的索引A.但是,如果我强制使用索引B,我得到我的结果1秒(快7倍)

很明显我的索引B比我的索引A快。我不能使用" force index"或"使用索引"命令,因为我的sql是从不支持此功能的框架生成的。

那么,为什么mysql不能自然地使用最快的索引。有没有办法告诉mysql总是使用某个索引而不添加"使用"或者"强迫"。

查询:

SELECT *
FROM soumission
LEFT OUTER JOIN region_administrative 
ON soumission.region_administrative_oid=region_administrative.oid 
WHERE (soumission.statut=2 
AND ((soumission.telephone LIKE '%007195155134070067132211046052045128049212213255%' 
OR (soumission.autre_telephone LIKE '%007195155134070067132211046052045128049212213255%')) 
OR (soumission.cellulaire LIKE '%007195155134070067132211046052045128049212213255%'))) 
ORDER BY soumission.date_confirmation DESC, soumission.numero;

我在多栏上添加了一个索引" statut","电话"," autre_telephone"," cellulaire"

如果我强制使用这个索引,我的查询速度提高了7倍,但如果我没有指定使用哪个索引,它会使用另一个索引(仅限于法定字段),这个速度要慢7倍

这里是解释我选择一个大的日期(使用错误的索引)

see it could use the ix_statut_date_confirmation2 but it it not

这是我选择一个小日期窗口时 see it's using the right index "ix_statut_date_confirmation_2"

2 个答案:

答案 0 :(得分:0)

这似乎就是你在做什么......

SELECT  s.*, ra.*
    FROM  soumission AS s
    LEFT OUTER JOIN  region_administrative AS ra  ON s.region_administrative_oid=ra.oid
    WHERE  s.statut = 2
      AND  (      s.telephone       LIKE '%007195155134070067132211046052045128049212213255%'
              OR  s.autre_telephone LIKE '%007195155134070067132211046052045128049212213255%'
              OR  s.cellulaire      LIKE '%007195155134070067132211046052045128049212213255%' 
           )
    ORDER BY  s.date_confirmation DESC, s.numero;

如果您不需要ra.*,请摆脱LEFT JOIN

您建议的多列索引是无用的,除非...... statut = 2少于20%的行,否则不会被使用。在这种情况下,它只会使用索引的第一列。

OR打败索引。 (见下文)

LIKE上的前导通配符会失败索引。你需要领先或尾随外卡吗?

DESCASCORDER BY的混合使用索引来避免排序。

那么,该怎么办?而不是为3个电话号码设置3列,而是有另一个电话号码表。然后为给定的输出提供任意数量的行。然后搜索该表可能会更快,因为避免OR - 但前提是你摆脱了前导通配符。

(这是一个非常长的电话号码!这是真的吗?)

答案 1 :(得分:0)

关于查询本身:

  1. 尝试避免使用前导LIKE通配符(在下面的查询中删除)。
  2. 将查询拆分为多个部分,并结合使用UNION子句,以便可以使用索引。
  3. 所以,创建这些索引:

    ALTER TABLE `region_administrative` ADD INDEX `region_administrativ_idx_oid` (`oid`);
    ALTER TABLE `soumission` ADD INDEX `soumission_idx_statut_oid_cellulaire` (`statut`,`region_administrative_oid`,`cellulaire`);
    ALTER TABLE `soumission` ADD INDEX `soumission_idx_statut_oid_telephone` (`statut`,`region_administrative_oid`,`autre_telephone`);
    ALTER TABLE `soumission` ADD INDEX `soumission_idx_statut_oid_telephone` (`statut`,`region_administrative_oid`,`telephone`);
    

    然后尝试此查询:

    SELECT
            * 
        FROM
            ((SELECT
                * 
            FROM
                soumission 
            LEFT OUTER JOIN
                region_administrative 
                    ON soumission.region_administrative_oid = region_administrative.oid 
            WHERE
                (
                    soumission.statut = 2 
                    AND (
                        (
                            soumission.cellulaire LIKE '007195155134070067132211046052045128049212213255%'
                        )
                    )
                ) 
            ORDER BY
                soumission.date_confirmation DESC,
                soumission.numero) 
        UNION
        DISTINCT (SELECT
            * 
        FROM
            soumission 
        LEFT OUTER JOIN
            region_administrative 
                ON soumission.region_administrative_oid = region_administrative.oid 
        WHERE
            (soumission.statut = 2 
            AND (((soumission.autre_telephone LIKE '007195155134070067132211046052045128049212213255%')))) 
        ORDER BY
            soumission.date_confirmation DESC,
            soumission.numero) 
    UNION
    DISTINCT (SELECT
        * 
    FROM
        soumission 
    LEFT OUTER JOIN
        region_administrative 
            ON soumission.region_administrative_oid = region_administrative.oid 
    WHERE
        (soumission.statut = 2 
        AND ((soumission.telephone LIKE '007195155134070067132211046052045128049212213255%'))) 
    ORDER BY
        soumission.date_confirmation DESC,
        soumission.numero)
    ) AS union1 
    ORDER BY
    union1.date_confirmation DESC,
    union1.numero