2011-01-30 23 views
9

Próbuję zmusić mój SQL do używania dwóch indeksów. Dołączam do stołu i chcę, żeby wykorzystywały krzyż pomiędzy dwoma indeksami. Konkretny termin Korzystanie przecinają i tu jest link do dokumentacji MySQL:Wymuś użycie MySQL na dwóch indeksach Dołącz

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

Czy istnieje jakiś sposób, aby wymusić tę realizację? Moje zapytanie go używało (i przyspieszyło), ale teraz z jakiegokolwiek powodu przestało.

Oto JOIN Chcę to zrobić. Oba indeksy chcę użyć kwerendy są scs.CONSUMER_ID_1 i 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

Proszę opublikować wersję MySql, definicje tabel i wyjście EXPLAIN. –

+0

Dodatkowo, możesz pokazać całe zapytanie ... lub przynajmniej resztę, która może nie uwzględniać "poufności" ... wybierz X z WhatTable ... Dołącz ... Gdzie ... grupuj według. .. – DRapp

Odpowiedz

13

See MySQL Docs dla 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 

Jak TheScrumMeister wskazał poniżej, to zależy od danych, czy dwa indeksy mogą być rzeczywiście używane jednocześnie.


Oto przykład, w którym należy wymusić dwukrotne pojawienie się tabeli, aby kontrolować wykonywanie zapytania i skrzyżowanie.

Użyj tego, aby utworzyć tabelę z> 100K rekordów, z około 1K wiersze zgodne z filtrem i in (2,3) i 1K wierszy pasujących 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; 

Kiedy robi:

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

dostajesz dokładnie 8 mecze:

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

Użyj EXPLAIN na zapytania powyżej, aby uzyskać:

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 

Nawet jeśli dodamy FORCE INDEX do kwerendy na dwóch indeksach EXPLAIN zwróci dokładnie to samo.

Żeby było zbierać w dwóch indeksów, a następnie przecinają je, użyj tego:

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 

Używaj frazę explain dostać:

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 

Dowodzi to, że indeksy są wykorzystywane . Ale to może, ale nie musi być szybsze w zależności od wielu innych czynników.

+0

Wierzę, że jeśli pierwotne wyjaśnienie było tylko przy użyciu jednego z indeksów, "FORCE INDEX" nie użyje ** obu **. –

+0

Myślałem, że indeks siły jest silniejszy niż indeks użycia, czyli jeśli w ogóle może być użyty, będzie. Czyżby 1 + 2 nie zostało zahartowane za skrzyżowanie? – RichardTheKiwi

+0

'indeks siły' jest silniejszy, i mówi optymalizatorowi zapytań, aby używał/wszystkich indeksów na liście. Jeśli więc oryginalny plan użył skanowania tabeli, ponieważ zdecydował, że skanowanie jest tańsze, zadziała. jeśli jednak - z jakiegoś powodu - optymalizator nie był w stanie użyć obu indeksów, "indeks siły ..." nie wystarczy. –

1

MySQL obsługuje tylko użycie pojedynczego indeksu na łączenie. Jeśli chcesz, aby wykorzystała dwie kolumny jako indeksy w łączeniu, powinieneś utworzyć pojedynczy indeks w tych dwóch kolumnach. Zauważ, że nie jest tak źle, jak się wydaje, ponieważ indeks powyżej (a, b) podwaja się jako indeks tylko dla a.

Zobacz the MySQL manual

MySQL nie może używać indeksu jeśli kolumny nie tworzą skrajnie lewą prefiksu indeksu.

+0

Nieprawdziwe z powodu optymalizacji "scalania indeksu". – Pacerier