mam następującą tabelę MySQL (uproszczony):Dlaczego usunięcie tego indeksu w MySQL przyspieszy moje zapytanie o 100x?
CREATE TABLE `track` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(256) NOT NULL,
`is_active` tinyint(1) NOT NULL,
PRIMARY KEY (`id`),
KEY `is_active` (`is_active`, `id`)
) ENGINE=MyISAM AUTO_INCREMENT=7495088 DEFAULT CHARSET=utf8
do „is_active” kolumna wyznacza wiersze, które chcę ignorować w większości, ale nie wszystkich, moich zapytaniami. Mam kilka zapytań, które okresowo odczytują porcje z tej tabeli. Jeden z nich wygląda następująco:
SELECT id,title from track where (track.is_active=1 and track.id > 5580702) ORDER BY id ASC LIMIT 10;
Wykonanie tej kwerendy trwa ponad minutę. Oto plan wykonanie:
> EXPLAIN SELECT id,title from track where (track.is_active=1 and track.id > 5580702) ORDER BY id ASC LIMIT 10;
+----+-------------+-------+------+----------------+--------+---------+-------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+----------------+--------+---------+-------+---------+-------------+
| 1 | SIMPLE | t | ref | PRIMARY,is_active | is_active | 1 | const | 3747543 | Using where |
+----+-------------+-------+------+----------------+--------+---------+-------+---------+-------------+
Teraz, jeśli powiem MySQL ignorować „” is_active indeksu, zapytanie dzieje się natychmiast.
> EXPLAIN SELECT id,title from track IGNORE INDEX(is_active) WHERE (track.is_active=1 AND track.id > 5580702) ORDER BY id ASC LIMIT 10;
+----+-------------+-------+-------+---------------+---------+---------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+------+---------+-------------+
| 1 | SIMPLE | t | range | PRIMARY | PRIMARY | 4 | NULL | 1597518 | Using where |
+----+-------------+-------+-------+---------------+---------+---------+------+---------+-------------+
Teraz, co jest naprawdę dziwne jest to, że jeśli wymusić MySQL użyć „” indeks is_active, kwerenda po raz kolejny stanie się natychmiast!
+----+-------------+-------+-------+---------------+---------+---------+------+---------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+---------+---------+------+---------+-------------+
| 1 | SIMPLE | t | range | is_active |is_active| 5 | NULL | 1866730 | Using where |
+----+-------------+-------+-------+---------------+---------+---------+------+---------+-------------+
Po prostu nie rozumiem tego zachowania. W indeksie "is_active" wiersze należy sortować według is_active, a następnie id. W moim zapytaniu używam zarówno kolumn "is_active", jak i "id", więc wydaje się, że trzeba tylko wykonać kilka przeskoków wokół drzewa, aby znaleźć identyfikatory, a następnie użyć tych identyfikatorów do pobrania tytułów z tabeli.
Co się dzieje?
EDIT: Więcej informacji na temat tego, co robię:
- cache zapytań jest wyłączone
- Bieg OPTYMALIZACJA TABELA i analizować TABELA nie miał wpływu
- 6.620.372 wierszy 'is_active' ustawioną na True. 874,714 wierszy ma "is_active" ustawione na False.
- Użycie FORCE INDEX (is_active) jeszcze raz przyspiesza zapytanie.
- wersja MySQL 5.1.54
Czyścisz pamięć podręczną przed testowaniem porównawczym, prawda? – dfb
Upewnij się także, że statystyki tabeli są aktualne, a indeksy są odbudowywane. (Jednak robi się to w MySQL ;-) –
Co stanie się, jeśli odwrócisz warunki WHERE? 'gdzie (track.id> 5580702 i track.is_active = 1)' – EJP