简体   繁体   English

MySQL不使用正确的索引

[英]Mysql not using right index

I have a framework that generate SQL. 我有一个生成SQL的框架。 one of the query is using my index "A" and return results in 7 seconds. 查询之一正在使用我的索引“ A”,并在7秒内返回结果。 I see that I can optimize this and I created an index "B". 我看到可以对其进行优化,并创建了索引“ B”。

now if I run "explain my query", it still use my index A. however, if I force the use of index B, I get my results in 1 seconds (7x faster) 现在,如果我运行“解释我的查询”,它仍然使用我的索引A。但是,如果我强制使用索引B,则我将在1秒内得到结果(快7倍)

so clearly my index B is faster than my index A. I can't use the "force index" or "use index" command as my sql is generated from a framework that does not support this. 因此很明显我的索引B比我的索引A快。我无法使用“强制索引”或“使用索引”命令,因为我的sql是从不支持此功能的框架生成的。

So, Why is mysql not naturally using the fastest index. 因此,为什么mysql不自然地使用最快的索引。 And is there a way I can tell mysql to always use a certain index without adding "use" or "force". 并且有一种方法可以告诉mysql始终使用特定索引,而无需添加“ use”或“ force”。

the query : 查询:

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;

i added an index on multiple column "statut","telephone","autre_telephone","cellulaire" 我在“ statut”,“ telephone”,“ autre_telephone”,“ cellulaire”多列上添加了索引

if I force using this index my query is 7x faster but if I dont specify which index to use, it use another index (only on statut field) which is 7x slower 如果我强制使用该索引,我的查询速度会提高7倍,但是如果我未指定要使用的索引,它将使用另一个索引(仅在状态字段上),速度会慢7倍

here is the explain if I select a large date period (using the wrong index) 这是我选择较大日期范围(使用错误的索引)的说明

看到它可以使用ix_statut_date_confirmation2,但它没有

here is When I select a small date window 这是当我选择一个小的日期窗口时 看到它使用正确的索引“ ix_statut_date_confirmation_2”

This seems to be what you are doing... 这似乎是您在做什么...

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;

If you don't need ra.* , get rid of the LEFT JOIN . 如果您不需要ra.* ,请摆脱LEFT JOIN

The multi-column index you propose is useless and won't be used unless... statut = 2 for less than 20% of the rows. 您建议的多列索引是无用的,除非... statut = 2 (少于20%的行),否则将不会使用该索引。 In that case, it will only use the first column of the index. 在这种情况下,它将仅使用索引的第一列。

OR defeats indexing. OR打败索引。 (See below) (见下文)

Leading wildcard on LIKE defeats indexing. LIKE通配符领先于索引。 Do you need the leading or trailing wild cards? 您是否需要前导或尾随通配符?

The mixing of DESC and ASC in the ORDER BY defeats using an index to avoid sorting. DESCASCORDER BY的混合使用索引以避免排序失败。

So, what to do? 那么该怎么办? Instead of having 3 columns for exactly 3 phone numbers, have another table for phone numbers. 而不是用3列来表示正好3个电话号码,而是使用另一个表来显示电话号码。 Then have any number of rows for a given soumission. 然后,对于给定的解决方案,可以有任意数量的行。 Then searching that table may be faster because of avoiding OR -- but only if you get rid the leading wildcard. 然后,由于避免使用OR因此搜索该表可能会更快-但前提是您必须摆脱前导通配符。

(That's an awfully long phone number! Is it real?) (这是一个非常长的电话号码!是真的吗?)

As to the query itself: 至于查询本身:

  1. Try avoiding the leading LIKE wildcard (removed in the query below). 尽量避免使用前导LIKE通配符(在下面的查询中已删除)。
  2. Split the query to several parts, combined with a UNION clause, so that indexes can be used. 将查询分为几个部分,并结合UNION子句,以便可以使用索引。

So, create these indexes: 因此,创建以下索引:

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`);

Then try this query: 然后尝试以下查询:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM