Force MySQL to use two indexes on a Join

前端 未结 2 507
攒了一身酷
攒了一身酷 2021-02-05 11:48

I am trying to force MySQL to use two indexes. I am joining a table and I want to utilize the cross between the two indexes. The specific term is Using intersect and here is a l

相关标签:
2条回答
  • 2021-02-05 12:35

    See MySQL Docs for FORCE INDEX.

    JOIN survey_customer_similarity AS scs 
    FORCE INDEX (CONSUMER_ID_1,CONSUMER_ID_2)
    ON
    cr.CONSUMER_ID=scs.CONSUMER_ID_2 
    AND cal.SENDER_CONSUMER_ID=scs.CONSUMER_ID_1 
    OR cr.CONSUMER_ID=scs.CONSUMER_ID_1 
    AND cal.SENDER_CONSUMER_ID=scs.CONSUMER_ID_2
    

    As TheScrumMeister has pointed out below, it depends on your data, whether two indexes can actually be used at once.


    Here's an example where you need to force the table to appear twice to control the query execution and intersection.

    Use this to create a table with >100K records, with roughly 1K rows matching the filter i in (2,3) and 1K rows matching j in (2,3):

    drop table if exists t1;
    create table t1 (id int auto_increment primary key, i int, j int);
    create index ix_t1_on_i on t1(i);
    create index ix_t1_on_j on t1(j);
    insert into t1 (i,j) values (2,2),(2,3),(4,5),(6,6),(2,6),(2,7),(3,2);
    insert into t1 (i,j) select i*2, j*2+i from t1;
    insert into t1 (i,j) select i*2, j*2+i from t1;
    insert into t1 (i,j) select i*2, j*2+i from t1;
    insert into t1 (i,j) select i*2, j*2+i from t1;
    insert into t1 (i,j) select i*2, j*2+i from t1;
    insert into t1 (i,j) select i*2, j*2+i from t1;
    insert into t1 (i,j) select i*2, j*2+i from t1;
    insert into t1 (i,j) select i*2, j*2+i from t1;
    insert into t1 (i,j) select i*2, j*2+i from t1;
    insert into t1 (i,j) select i*2, j*2+i from t1;
    insert into t1 (i,j) select i*2, j*2+i from t1;
    insert into t1 (i,j) select i*2, j*2+i from t1;
    insert into t1 (i,j) select i, j from t1;
    insert into t1 (i,j) select i, j from t1;
    insert into t1 (i,j) select 2, j from t1 where not j in (2,3) limit 1000;
    insert into t1 (i,j) select i, 3 from t1 where not i in (2,3) limit 1000;
    

    When doing:

    select t.* from t1 as t where t.i=2 and t.j=3 or t.i=3 and t.j=2
    

    you get exactly 8 matches:

    +-------+------+------+
    | id    | i    | j    |
    +-------+------+------+
    |     7 |    3 |    2 |
    | 28679 |    3 |    2 |
    | 57351 |    3 |    2 |
    | 86023 |    3 |    2 |
    |     2 |    2 |    3 |
    | 28674 |    2 |    3 |
    | 57346 |    2 |    3 |
    | 86018 |    2 |    3 |
    +-------+------+------+
    

    Use EXPLAIN on the query above to get:

    id | select_type | table | type  | possible_keys         | key        | key_len | ref  | rows | Extra
    1  | SIMPLE      | t     | range | ix_t1_on_i,ix_t1_on_j | ix_t1_on_j | 5       | NULL | 1012 | Using where
    

    Even if we add FORCE INDEX to the query on two indexes EXPLAIN will return the exact same thing.

    To make it collect across two indexes, and then intersect them, use this:

    select t.* from t1 as a force index(ix_t1_on_i)
    
    join t1 as b force index(ix_t1_on_j) on a.id=b.id
    
    where a.i=2 and b.j=3 or a.i=3 and b.j=2
    

    Use that query with explain to get:

    id | select_type | table | type  | possible_keys | key        | key_len | ref  | rows | Extra
    1  | SIMPLE      | a     | range | ix_t1_on_i    | ix_t1_on_i | 5       | NULL | 1019 | Using where
    1  | SIMPLE      | b     | range | ix_t1_on_j    | ix_t1_on_j | 5       | NULL | 1012 | Using where; Using index
    

    This proves that the indexes are being used. But that may or may not be faster depending on many other factors.

    0 讨论(0)
  • 2021-02-05 12:47

    MySQL only supports using a single index per join. If you want it to utilize two columns as indices in the join, you should create a single index over those two columns. Note that this isn't as bad as it seems, because an index over (a,b) doubles as an index over just a.

    See the MySQL manual

    MySQL cannot use an index if the columns do not form a leftmost prefix of the index.

    0 讨论(0)
提交回复
热议问题