MySQL - медленный базовый 2-табличный запрос - где, индекс?

У меня есть запрос MySQL 5.0, который регулярно занимает более 14 секунд, вызывается с веб-страницы, и пользователи нетерпеливы. Это довольно просто — выбрать 11 столбцов из 2 таблиц. У меня три вопроса:

  1. Имеет ли значение место соединения?
  2. Имеет ли значение порядок предложения where или MySQL будет оптимизировать?
  3. Поможет ли и индекс в моем случае?

SQL:

select table1.id, table1.DateOpened, table1.Status, table2.Name, etc
from (table1 join table2 on((table1.CurrentName = table2.id))) 
where table1.Type = 'Add' and (Status = 'Open' OR Status = 'Pending');

информация о таблице/столбце:

table1 has 750,000 rows, table2 1.5M rows.
indexed: table1.id, table2.id
INT columns: id, table1.CurrentName
table1.Status = always populated with 1 of 4 values, 
                maybe 300 are 'Open' or 'Pending'
table1.Type = 3 possible values: 'Add', 'Change', or null
  1. Есть ли какое-либо преимущество JOINing в FROM по сравнению с добавлением «table1.CurrentName = table2.id» в предложении WHERE?

  2. Есть 3 предложения WHERE (с соединением). Я запустил EXPLAIN с различными комбинациями ордеров, и результаты оказались одинаковыми.

  3. Я думал, что добавление индекса в table1.CurrentName может помочь, но теперь я думаю, что нет. Я изменил запрос, удалив ссылки на table2, но он по-прежнему работал медленно. (см. 3б)

  4. Похоже, что основная часть замедления может быть вызвана просто чтением 800K записей при просмотре значений Type и Status. Имеет ли смысл индексировать эти два столбца, где есть только 3 или 4 возможных значения? Я думал, что это имеет смысл только тогда, когда есть больше уникальных значений.

объяснить результаты:

+----+-------------+--------+--------+---------------+---------+---------+-----------------------+--------+-------------+ 
| id | select_type | table  | type   | possible_keys | key     | key_len | ref                   | rows   | Extra       |         
+----+-------------+--------+--------+---------------+---------+---------+-----------------------+--------+-------------+ 
|  1 | SIMPLE      | table1 | ALL    | CurrentName   | NULL    | NULL    | NULL                  | 733190 | Using where | 
|  1 | SIMPLE      | table2 | eq_ref | PRIMARY       | PRIMARY | 4       | db.table1.CurrentName | 1      |             | 
+----+-------------+--------+--------+---------------+---------+---------+-----------------------+--------+-------------+ 
2 rows in set (0.00 sec)

person snowmanjack    schedule 01.12.2010    source источник
comment
@Сатья. Показанный EXPLAIN указывает, что имеется индекс для id. Это первичный ключ таблицы2.   -  person Riedsio    schedule 02.12.2010


Ответы (1)


Имеет ли значение место соединения?

Порядок их написания не имеет значения для ВНУТРЕННИХ СОЕДИНЕНИЙ.

Имеет ли значение порядок предложения where или MySQL будет оптимизировать?

Нет. Порядок написания в предложении WHERE не имеет значения для синтаксического анализатора и оптимизатора запросов MySQL.

Поможет ли и индекс в моем случае?

Потенциально. Составной индекс type_status (Тип, Статус) в таблице 1 может помочь, поскольку именно здесь ваше предложение WHERE может уменьшить количество прочитанных начальных строк.

Есть ли какое-либо преимущество JOINing в FROM по сравнению с добавлением «table1.CurrentName = table2.id» в предложении WHERE?

Для INNER JOIN не имеет значения, находится ли условие JOIN в предложении FROM или в предложении WHERE.

Я думал, что добавление индекса в table1.CurrentName может помочь, но теперь я думаю, что нет. Я изменил запрос, удалив ссылки на table2, но он по-прежнему работал медленно. (см. 3б)

Индекс для table1.CurrentName не поможет запросу.

Похоже, что основная часть замедления может быть вызвана просто чтением 800K записей при просмотре значений Type и Status.

Это подтверждает мою мысль выше. Чтобы добавить составной индекс (что потенциально не очень хорошо делать в Интернете), это будет что-то вроде

ALTER TABLE table1 ADD INDEX type_status (Type, Status);

Я думал, что это имеет смысл только тогда, когда есть больше уникальных значений.

Избирательность определенно помогает, но высокая кардинальность — не единственный подходящий контекст.

person Riedsio    schedule 01.12.2010
comment
Отличные и исчерпывающие ответы, спасибо! Я посмотрю составной индекс. - person snowmanjack; 02.12.2010
comment
Вам действительно нужно выбрать все эти строки? Я не могу представить веб-страницу с более чем 700 тысячами строк. Вы не пропустили LIMIT в своем запросе? Однако составной/составной индекс может немного помочь. - person johno; 02.12.2010
comment
@ Джоно, хорошая мысль. Лучшие данные — это данные, которые вам не нужно извлекать. :) - person Riedsio; 02.12.2010
comment
+1 - еще одно: если ваш индекс в таблице 1 был (Type, Status, CurrentName), то и предложение where, и предложение соединения могут быть удовлетворены через индекс. Это может сэкономить несколько чтений таблицы данных (хотя посмотрите, что думает объяснение: оптимизатору сложно угадать дважды). - person Martin; 02.12.2010
comment
Если бы ваш индекс в таблице 1 был (тип, статус, текущее имя), он ничего не сохранил бы, поскольку ему все равно нужно будет попадать на диск для каждой таблицы 1.DateOpened. Если вы действительно хотите быть уверены, вы всегда можете попробовать разные индексы в текстовом поле и посмотреть переменные % обработчика состояния сеанса. - person Riedsio; 02.12.2010
comment
@ Мартин, у тебя таблицы MyISAM или InnoDB? - person Riedsio; 02.12.2010
comment
@ Riedsio - не уверен в MyISAM или InnoDB, я не настраивал БД, не знаю, как это проверить. (Я разработчик Java, а не администратор баз данных, поэтому у меня ограниченный опыт.) - person snowmanjack; 02.12.2010
comment
@johno - Предложение WHERE ограничивает количество строк примерно до 300 на основе наших данных. Но вы правы - у меня нет полного запроса, только базовый запрос. Через страницу мы ограничиваем результаты до 25, затем с помощью ссылок «следующая/назад» мы смещаем результаты на 25 за раз. - person snowmanjack; 02.12.2010
comment
@snowmanjack - Вы можете определить ENGINE, выполнив SHOW TABLE STATUS LIKE 'table' или SHOW CREATE TABLE table. - person Riedsio; 02.12.2010