TL; DR
При запросе к той же таблице, почему первый запрос ниже (сканирует 20 строк) занимает значительно больше времени, чем второй (сканирует 35k + строк)?
Первый запрос:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE Groups range <lots of keys> group_name_ip_address_idx 317 NULL 20 Using index condition; Using where
Второй запрос:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE Groups ref_or_null <lots of keys> email_address_idx 768 const 35415 Using index condition; Using where
Я использую «строки» в объяснении как прямой индикатор производительности запроса (что может быть не так?), Но все же запрос с 20 строками занимает гораздо больше времени, чем смущает запрос 35k. Не специалист по SQL, кто-нибудь может объяснить мне, что может вызвать это?
Более длинная версия:
У меня есть таблица «Группы», в которой есть поле «имя_группы» и еще 20 полей («field_1», «field_2», ..., «field_20») с информацией о клиенте.
Я использую эту таблицу, чтобы определить, когда я вижу информацию о клиенте, какой группе (группам) он соответствует. Для фиктивного примера, если в таблице есть запись, в которой имя группы равно «US male», а все 20 полей имеют нулевое значение, за исключением «гражданства» «US» и «пол» «male», то это означает, что когда я вижу клиент с гражданством "США" и полом "мужчина", он соответствует группе "мужчина США".
Я использую этот запрос (Query1), который занимает 3 ~ 5 мс для достижения этой цели:
select * from Groups
where group_name = "US male"
and (field_1 = "something1" or field_1 is null)
and (field_2 = "something2" or field_2 is null)
and ... and (field_20 = "something20" or field_20 is null)
Эти "что-то" представляют информацию о текущем клиенте, которую я хочу знать, с какими группами он / она соответствует. Так что если этот запрос что-то возвращает, это означает совпадение; в противном случае не совпадают.
Объяснить вывод вышеуказанного запроса:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE Groups ref_or_null <lots of keys> group_name_email_address_idx 962 const,const 2 Using index condition; Using where
Обратите внимание, что один клиент может соответствовать нескольким группам, поэтому для N имени группы мне понадобится N запросов, как указано выше. Теперь, когда N становится больше, я хочу использовать один отдельный запрос вместо N маленьких запросов, чтобы сделать то же самое, и вот где я застрял.
Сначала я попытался удалить условие group_name = "XXXX"
в where
- выбрать все подходящие группы вместо проверки по одной (Query2).
select * from Groups
where (field_1 = "something1" or field_1 is null)
and (field_2 = "something2" or field_2 is null)
and ... and (field_20 = "something20" or field_20 is null)
объяснить выходы:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE Groups ref_or_null <lots of keys> email_address_idx 768 const 35415 Using index condition; Using where
Это медленно (~ 70 мс), потому что он не может использовать индексы, которым нужно имя группы, которые являются наиболее эффективными, потому что имя_группы имеет наименьшее количество элементов. (количество строк, необходимых для сканирования, составляет 35 КБ по сравнению с 2 в первом запросе). Так что это не очень хорошо сработало.
Затем, чтобы запрос использовал индексы имен групп, я добавил group_name in (<all group names>)
в where
(Query3):
select * from Groups
where group_name in ("group1", "group2", ..., "groupN")
and (field_1 = "something1" or field_1 is null)
and (field_2 = "something2" or field_2 is null)
and ... and (field_20 = "something20" or field_20 is null)
объяснить выходы:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE Groups range <lots of keys> group_name_ip_address_idx 317 NULL 20 Using index condition; Using where
Я увидел, что нужно отсканировать 20 строк, что значительно лучше, чем 35415, поэтому я ожидал, что он будет работать быстро. Однако когда я попытался запустить его, на самом деле это заняло гораздо больше времени, чем Query2 (примерно в 20 раз), который сломал мой сервис.
После всего этого я очень растерялся, почему запрос, который сканирует 20 строк, занимает намного больше времени, чем запрос, который сканирует 35 тыс. Строк? Я неправильно читаю выводы объяснения?