【问题标题】:Mysql not using right indexMysql没有使用正确的索引
【发布时间】:2018-09-16 21:34:59
【问题描述】:

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

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

很明显,我的索引 B 比我的索引 A 快。我不能使用“强制索引”或“使用索引”命令,因为我的 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”、“telephone”、“autre_telephone”、“cellulaire”上添加了索引

如果我强制使用此索引,我的查询速度会快 7 倍,但如果我不指定要使用的索引,它会使用另一个索引(仅在 statut 字段上),速度会慢 7 倍

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

这是当我选择一个小日期窗口时

【问题讨论】:

  • 在不了解表结构和所讨论的查询的情况下,不可能回答有关优化和索引使用的问题。
  • 我添加了详细查询
  • @Yannick Richard - 向我们展示查询的解释。注意:以“%”开头的like总是全表扫描
  • 我添加了两个解释,一个使用错误索引的大日期周期,一个使用正确索引的小日期范围的完全相同的查询。要使用的正确索引是“ix_statut_date_confirmation2”
  • 您的查询有两个表;你的EXPLAINs 有 3 张桌子——??? “日期期间”条款在哪里???

标签: mysql sql indexing


【解决方案1】:

关于查询本身:

  1. 尽量避免使用前导 LIKE 通配符(已在下面的查询中删除)。
  2. 将查询拆分为多个部分,并结合 UNION 子句,以便可以使用索引。

所以,创建这些索引:

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

【讨论】:

    【解决方案2】:

    这似乎是你正在做的......

    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 上的前导通配符会破坏索引。您需要前导通配符还是尾随通配符?

    ORDER BYDESCASC 的混合使用索引来避免排序失败。

    那么,该怎么办?不要为正好 3 个电话号码设置 3 列,而是为电话号码设置另一个表格。然后对于给定的 soumission 有任意数量的行。然后搜索该表可能会更快,因为避免了OR——但前提是你去掉了 leading 通配符。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-07-20
      • 2012-08-11
      • 1970-01-01
      • 1970-01-01
      • 2019-06-26
      • 2013-12-02
      相关资源
      最近更新 更多