2016-01-07 2 views
0
определение

Таблицы:Почему мой индекс не используется в выборе тузды

CREATE TABLE `titles` (
    `emp_no` int(11) NOT NULL, 
    `title` varchar(50) NOT NULL, 
    `from_date` date NOT NULL, 
    `to_date` date DEFAULT NULL, 
    PRIMARY KEY (`emp_no`,`title`,`from_date`), 

) ENGINE=InnoDB DEFAULT CHARSET=utf8 

Этого запрос:

EXPLAIN SELECT * FROM employees.titles WHERE emp_no < '10010' and title='Senior Engineer'; 
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+ 
| id | select_type | table | type | possible_keys | key  | key_len | ref | rows | Extra  | 
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+ 
| 1 | SIMPLE  | titles | range | PRIMARY  | PRIMARY | 4  | NULL | 16 | Using where | 
+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+ 

Мой вопрос, почему только первый столбец может использовать индекс? Я знаю, что многие статьи/документы дают такой вывод, но я хотел бы узнать подробное объяснение.

Моего понимания, MySQL может сканировать индекс ВТКЕЯ и найти коллекцию ключей, которые соответствуют emp_no < '10010', а затем фильтровать их на title='Senior Engineer', почему он сказал, что from_data столбец не может использовать индекс? (Кстати, я думаю, что знаю, как работает B + Tree).

Спасибо.


Ниже выход объяснить формат = JSON:

{ 
    "query_block": { 
    "select_id": 1, 
    "cost_info": { 
     "query_cost": "1.41" 
    }, 
    "table": { 
     "table_name": "titles", 
     "access_type": "range", 
     "possible_keys": [ 
     "PRIMARY" 
     ], 
     "key": "PRIMARY", 
     "used_key_parts": [ 
     "emp_no" 
     ], 
     "key_length": "4", 
     "rows_examined_per_scan": 1, 
     "rows_produced_per_join": 1, 
     "filtered": "100.00", 
     "cost_info": { 
     "read_cost": "1.21", 
     "eval_cost": "0.20", 
     "prefix_cost": "1.41", 
     "data_read_per_join": "168" 
     }, 
     "used_columns": [ 
     "emp_no", 
     "title", 
     "from_date", 
     "to_date" 
     ], 
     "attached_condition": "((`employees`.`titles`.`emp_no` < '10010') and (`employees`.`titles`.`title` = 'Senior Engineer'))" 
    } 
    } 
} 

ответ

0

Проблема здесь ваша таблица очень мала, даже если индекс снижения поиска стоимости, с использованием индекса также саму стоимость.

Так что для небольших таблиц стоимость использования индекса больше, чем просто прочитать всю таблицу. Попробуйте включить больше строк и повторите попытку.

0
WHERE 'emp_no' < ... AND ... 
KEY(emp_no, ...) 

Поскольку emp_no используется в «диапазоне» («<»), будет использоваться только emp_no ключа.

Обводя ключ: (title, emp_no, ...), могут использоваться как title, так и emp_no.

Cookbook on indexing.

Но заметьте ... Это изменение индекса сделает SELECT работать «лучше». Но что другие вопросов у вас есть? Вы может потребность иметь более одного индекса, возможно:

PRIMARY KEY(emp_no, title, from_date), 
INDEX(title, emp_no) 

Назад к первоначальному вопросу. EXPLAINделает показывает, что он использует «диапазон». Но он не говорит, проверяется ли title. Какую версию MySQL вы используете? В более новых версиях есть «индексное нажатие кнопки», которое, скорее всего, сделает тест на title, о котором вы упоминаете. EXPLAIN FORMAT=JSON SELECT ... должен сказать, делает ли он это.

Тем не менее, имея индекс , начинающийся с title, более эффективен, потому что ему не нужно утомительно переходить к титрам, которые не применяются. Все соответствующие строки являются последовательными.

Редактировать Объясняя EXPLAIN

Он говорит, что он использует «диапазон», и используя («used_key_parts») только emp_no часть индекса.Тем не менее, он говорит, что «used_columns» - это все 4 столбца, даже больше, чем в используемом KEY. Чтобы объяснить ...

PRIMARY KEY в InnoDB «сгруппирован» с данными - то есть они находятся в одинаковых BTree.

Исполнение будет использовать только emp_no < '10010' - Оно начнется в начале таблицы и дойдет до, но не включится, первая строка с emp_no = '10010'. Как она идет, она (в частности, InnoDB двигатель) будет применять "прикрепленное состояние" "((employees. titles. emp_no < '10010') и (employees. titles. title = 'Старшего инженера'))", чтобы отфильтровать любые строки, которые не проходят этот тест. (Здесь я говорю, что он «перешагивает» на неинтересные значения title.)

Это сканирование «данных» Бритти. Если вы добавите INDEX(title, emp_no), вы, вероятно, найдете совсем другой JSON. Отправьте его; Я объясню.

(Примечание:. Если «слишком много» EMPS является «старшими инженерами», оптимизатор может принять решение для сканирования данных вместо того, чтобы использовать новый индекс)

+0

Спасибо за ответ и ссылку, MySQL версия 5.7 .10 - последний, добавленный json-выход, но я думаю, что key_length показывает всю информацию. Вы предлагаете хорошо, но я не настраиваю запрос здесь, это надуманный пример, и я просто хочу знать, почему. – July

+0

Но вы упомянули «последовательный» в своем последнем предложении, возможно, именно по этой причине он не «перешагнул». – July

+0

См. «Объяснение EXPLAIN». –