Co do zasady, MySQL nie umie wykorzystać więcej niż jeden indeks do danego zapytania. Jeśli możliwe jest skorzystanie z indeksu, optimizer stara się wybrać najbardziej optymalny z dostępnych indeksów. Może to być indeks obejmujący kilka kolumn, ale jest to jeden indeks. Od tej zasady jest jednak jeden wyjątek – Index Merge. Jest to algorytm, który umożliwia połączenie wyników kilku skanów różnych indeksów w jeden. Tak aby być precyzyjnym, są to trzy różne algorytmy:

– Index Merge Intersection, który ma zastosowanie np. do następujących zapytań:

SELECT * FROM dowolna_tabela WHERE kol1=1 AND kol2=2 AND kol3=3;
SELECT * FROM tabela_innodb WHERE klucz_glowny < 100 AND kol2=13;

Na wszystkie kolumny muszą być nałożone indeksy. Jeśli jakiś indeks nałożymy na dwie (lub więcej) kolumny, to dodatkowo pojawia się możliwość wykorzystania tego algorytmu w następującym zapytaniu:

SELECT * FROM dowolna_tabela WHERE (kol1_w_indeksie1=10 AND kol2_w_indeksie1=12) AND kol3_w_jakims_innym_indeksie=15;

– Index Merge Union, który ma zastosowanie do następujących rodzajów zapytań:

SELECT * FROM dowolna_tabela WHERE kol1=2 OR kol2=5 OR kol3=15;
SELECT * FROM dowolna_tabela WHERE (kol1=1 AND kol2=5) OR (kol3=12 AND kol4=72) OR kol5='cokolwiek';

Czyli, da się go zastosować gdy mamy sumę wyrażeń a każde z nich spełnia warunki zastosowania algorytmu Index Merge Intersection.

– Index Merge Sort-Union – jest on wykorzystywany w zapytaniach, których warunki dotyczą zakresów i są połączone przez OR, a algorytm Index Merge Union nie może zostać tam zastosowany. Przykładowe takie zapytania to:

SELECT * FROM dowolna_tabela WHERE nieindeksowana_kolumna=12 AND (kol1 > 4 OR kol2=13);
SELECT * FROM dowolna_tabela WHERE kol1 < 35 OR kol2 < 2;

W przypadku zastosowania EXPLAIN na tego typu zapytania otrzymujemy informację jakie indeksy są wykorzystywane i jaki algorytm został zastosowany:

mysql> EXPLAIN SELECT id FROM tab WHERE a=1 AND b=2 AND b=7\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: tab
type: index_merge
possible_keys: b,c,a
key: b,c,a
key_len: 1,1,1
ref: NULL
rows: 22328
Extra: Using intersect(b,c,a); Using where
1 row in set (0.21 sec)

mysql> EXPLAIN SELECT id FROM tab WHERE a=1 OR b=2\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: OFERTY
type: index_merge
possible_keys: b,a
key: a,b
key_len: 1,1
ref: NULL
rows: 409526
Extra: Using union(a,b); Using where
1 row in set (1.73 sec)

mysql> EXPLAIN SELECT id FROM tab WHERE a=1 OR b=2 AND c=7\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: OFERTY
type: index_merge
possible_keys: b,c,a
key: a,b,c
key_len: 1,1,1
ref: NULL
rows: 357208
Extra: Using union(a,intersect(b,c)); Using where
1 row in set (0.11 sec)

Podstawową zaletą takiego algorytmu jest to, że w przypadku, gdy piszemy zapytania do jednej tabeli, ale o zmieniających się często kombinacjach kolumn w warunku WHERE, można pozakładać indeksy na pojedyncze kolumny i przy pomocy tego algorytmu z nich korzystać. Nie jest to tak wydajne rozwiązanie jak zastosowanie indeksu na wszystkie kolumny wykorzystywane w danym zapytaniu, ale gdy wykorzystywanych kombinacji jest dużo, może się opłacać. Przykładowo, weźmy tabelę z pięcioma kolumnami. W zapytaniach wykorzystywane są wszystkie kombinacje z równomierną częstotliwością. Do skorzystania z algorytmu Index Merge wystarczy pięć indeksów. Aby pokryć indeksami wszystkie kombinacje pięciu kolumn, trzeba tych indeksów więcej. Gdy tabela dobija do 1GB, może się okazać że założenie dodatkowych kilku potrzebnych indeksów spowoduje, że łączna ich wielkość sięgnie kilku gigabajtów. Tym bardziej, że indeks na jedną kolumnę zawsze będzie mniejszy, niż indeks na kolumn pięć. Takie zwiększenie wielkości indeksów może być problematyczne, szczególnie jeśli stosujemy MyISAM i co jakiś czas zdarza się konieczność naprawy takiej tabeli. Pół dnia z głowy. Dodatkowo, zwiększa się ilość pamięci potrzebnej na przechowywanie takiego indeksu, duży indeks nie jest już tak szybki i wydajny jak mniejszy i tak dalej i tak dalej – wad takiego rozwiązania jest sporo.

Warto znać i pamiętać o takiej możliwości, jaką daje MySQL. Nawet pomimo tego że nie jest to najbardziej optymalne z punktu widzenia wydajności, czasem jest to jedyne sensowne wyjście.