简体   繁体   中英

Mysql not using right index

I have a framework that generate SQL. one of the query is using my index "A" and return results in 7 seconds. I see that I can optimize this and I created an index "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)

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.

So, Why is mysql not naturally using the fastest index. And is there a way I can tell mysql to always use a certain index without adding "use" or "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"

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

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 .

The multi-column index you propose is useless and won't be used unless... statut = 2 for less than 20% of the rows. In that case, it will only use the first column of the index.

OR defeats indexing. (See below)

Leading wildcard on LIKE defeats indexing. 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.

So, what to do? Instead of having 3 columns for exactly 3 phone numbers, have another table for phone numbers. 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.

(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).
  2. Split the query to several parts, combined with a UNION clause, so that indexes can be used.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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