Заставить MySQL использовать два индекса в Join - PullRequest
12 голосов
/ 30 января 2011

Я пытаюсь заставить MySQL использовать два индекса.Я присоединяюсь к таблице и хочу использовать пересечение между двумя индексами.Конкретный термин «Использование пересечения» и вот ссылка на документацию MySQL:

http://dev.mysql.com/doc/refman/5.0/en/index-merge-optimization.html

Есть ли способ заставить эту реализацию?Мой запрос использовал его (и он ускорился), но теперь по какой-то причине он остановился.

Вот соединение, на котором я хочу сделать это.Я хочу, чтобы запрос использовал два индекса: scs.CONSUMER_ID_1 и scs_CONSUMER_ID_2

JOIN survey_customer_similarity AS scs
    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

Ответы [ 2 ]

17 голосов
/ 30 января 2011

См. Документы MySQL для 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

Как указал TheScrumMeister ниже, от ваших данных зависит, могут ли фактически использоваться два индекса одновременно.


Вот пример, где необходимо заставить таблицу появляться дважды, чтобы контролировать выполнение и пересечение запроса.

Используйте это, чтобы создать таблицу с> 100K записями, примерно с 1K строк, соответствующих фильтру i in (2,3) и 1K строк, соответствующих 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;

При выполнении:

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

вы получите ровно 8 матчей:

+-------+------+------+
| 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 |
+-------+------+------+

Используйте EXPLAIN в запросе выше, чтобы получить:

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

Даже если мы добавим FORCE INDEX к запросу по двум индексам, EXPLAIN вернет точно такую ​​же вещь .

Чтобы собрать его по двум индексам, а затем пересечь их, используйте это:

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

Используйте этот запрос с explain, чтобы получить:

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

Это доказывает, что индексы используются. Но это может быть или не быть быстрее в зависимости от многих других факторов.

1 голос
/ 30 января 2011

MySQL поддерживает использование только одного индекса на соединение.Если вы хотите, чтобы в качестве индексов в соединении использовались два столбца, вы должны создать один индекс для этих двух столбцов.Обратите внимание, что это не так плохо, как кажется, потому что индекс над (a, b) удваивается как индекс над просто.

См. руководство по MySQL

MySQL не может использовать индекс, если столбцы не образуют крайний левый префикс индекса.

...