2011-01-30 15 views
9

Estoy tratando de forzar a mi SQL a utilizar dos índices. Me estoy uniendo a una mesa y quiero que utilicen el cruce entre dos índices. El término específico está utilizando se cruzan y aquí hay un enlace a la documentación de MySQL:Fuerza a MySQL a usar dos índices en un join

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

¿Hay alguna manera de forzar esta aplicación? Mi consulta lo estaba usando (y aceleró), pero ahora por cualquier razón se ha detenido.

Aquí está el JOIN Quiero hacer esto en. Los dos índices que desea que la consulta a utilizar son scs.CONSUMER_ID_1 y 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

Por favor, publique la versión MySql, las definiciones de tablas y la salida EXPLAIN. –

+0

Además, ¿puede mostrar toda la consulta ... o al menos la mayor parte del resto que podría no ser una consideración de "confidencial" ... seleccione X de WhatTable ... Únase ... Donde ... grupo de. .. – DRapp

Respuesta

13

Ver MySQL Docs para 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 

Como TheScrumMeister ha señalado a continuación, que depende de sus datos, ya sea en realidad dos índices se pueden utilizar a la vez.


Aquí hay un ejemplo en el que debe forzar que la tabla aparezca dos veces para controlar la ejecución de la consulta y la intersección.

Utilice esta opción para crear una tabla con> 100K registros, con aproximadamente 1K filas que coincidan con el filtro i in (2,3) y 1K filas que coincidan con 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; 

Al hacer:

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

se obtiene exactamente 8 partidos

+-------+------+------+ 
| 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 en la consulta anterior para obtener:

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 

Incluso si añadimos FORCE INDEX a la consulta en dos índices EXPLAIN devolverá el exactamente lo mismo.

Para que sea recoger a través de dos índices, y luego se cruzan, utilice esto:

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 

uso que consultar con explain llegar:

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 

Esto demuestra que se están utilizando los índices . Pero eso puede o no ser más rápido dependiendo de muchos otros factores.

+0

Creo que si la explicación original estaba usando solo 1 de los índices, 'FORCE INDEX' no lo forzará a usar ** both **. –

+0

El índice de fuerza de pensamiento es más fuerte que el índice de uso, es decir, si se puede usar, lo será. Entonces, ¿no se usaría hash 1 + 2 para la intersección? – RichardTheKiwi

+0

'force index' es más fuerte, y le dice al optimizador de consultas que use cualquiera/todos los índices en la lista. Entonces, si el plan original usó un escaneo de tabla porque decidió que un escaneo es más económico, funcionará. sin embargo, si, por cualquier razón, el optimizador no pudo usar ambos índices, 'force index ...' no funcionará. –

1

MySQL solo admite el uso de un solo índice por combinación. Si desea que utilice dos columnas como índices en la combinación, debe crear un único índice sobre esas dos columnas. Tenga en cuenta que esto no es tan malo como parece, porque un índice sobre (a, b) se dobla como un índice en solo a.

Ver the MySQL manual

MySQL no puede usar un índice si las columnas no forman un prefijo a la izquierda del índice.

+0

No es cierto debido a las optimizaciones de 'index merge'. – Pacerier

Cuestiones relacionadas