У меня в голове есть SQL, который должен работать менее чем за 1 секунду:

SELECT mem.`epid`,
       mem.`model_id`,
       em.`UKM_Make`,
       em.`UKM_Model`,
       em.`UKM_CCM`,
       em.`UKM_Submodel`,
       em.`Year`,
       em.`UKM_StreetName`,
       f.`fit_part_number`
FROM `table_one` AS mem
INNER JOIN `table_two` em ON mem.`epid` = em.`ePID`
INNER JOIN `table_three` f ON `mem`.`model_id` = f.`fit_model_id`
LIMIT 1;

Когда я запускаю терминал, этот SQL выполняется за 16 секунд. Однако, если я удалю строку:

INNER JOIN `table_three` f ON `mem`.`model_id` = f.`fit_model_id`

Затем он выполняется за 0,03 секунды. К сожалению для меня, я не знаю, как отлаживать проблемы с производительностью MYSQL. Это приводит к тому, что моему PHP-скрипту не хватает памяти при попытке выполнить запрос.

Вот мои структуры таблиц:

table_one

+----------+---------+------+-----+---------+-------+
| Field    | Type    | Null | Key | Default | Extra |
+----------+---------+------+-----+---------+-------+
| epid     | int(11) | YES  |     | NULL    |       |
| model_id | int(11) | YES  |     | NULL    |       |
+----------+---------+------+-----+---------+-------+

table_two

+----------------+--------------+------+-----+---------+-------+
| Field          | Type         | Null | Key | Default | Extra |
+----------------+--------------+------+-----+---------+-------+
| id             | int(11)      | NO   | PRI | NULL    |       |
| ePID           | int(11)      | NO   |     | NULL    |       |
| UKM_Make       | varchar(100) | NO   |     | NULL    |       |
| UKM_Model      | varchar(100) | NO   |     | NULL    |       |
| UKM_CCM        | int(11)      | NO   |     | NULL    |       |
| UKM_Submodel   | varchar(100) | NO   |     | NULL    |       |
| Year           | int(11)      | NO   |     | NULL    |       |
| UKM_StreetName | varchar(100) | NO   |     | NULL    |       |
| Vehicle Type   | varchar(100) | NO   |     | NULL    |       |
+----------------+--------------+------+-----+---------+-------+

table_three

+-----------------+-------------+------+-----+---------+----------------+
| Field           | Type        | Null | Key | Default | Extra          |
+-----------------+-------------+------+-----+---------+----------------+
| fit_fitment_id  | int(11)     | NO   | PRI | NULL    | auto_increment |
| fit_part_number | varchar(50) | NO   |     | NULL    |                |
| fit_model_id    | int(11)     | YES  |     | NULL    |                |
| fit_year_start  | varchar(4)  | YES  |     | NULL    |                |
| fit_year_end    | varchar(4)  | YES  |     | NULL    |                |
+-----------------+-------------+------+-----+---------+----------------+

Вышеупомянутое выводится из describe $table_name

Есть ли что-то, чего мне явно не хватает, и если нет, как я могу попытаться выяснить, почему включение table_three вызывает такое медленное время отклика?

ИЗМЕНИТЬ ОДИН:

После предложения индексирования (используется CREATE INDEX fit_model ON table_three (fit_model_id), он выполняет запрос за 0,00 секунды (в MYSQL). Удаление ограничения все еще выполняется после выполнения предложения ... так что не совсем так. Предложение Антона об использовании EXPLAIN I использовал его и получил такой вывод:

+------+-------------+-------+------+---------------+-----------+---------+----------------------+-------+-------------------------------------------------+
| id   | select_type | table | type | possible_keys | key       | key_len | ref                  | rows  | Extra                                           |
+------+-------------+-------+------+---------------+-----------+---------+----------------------+-------+-------------------------------------------------+
|    1 | SIMPLE      | mem   | ALL  | NULL          | NULL      | NULL    | NULL                 |  5587 | Using where                                     |
|    1 | SIMPLE      | f     | ref  | fit_model     | fit_model | 5       | mastern.mem.model_id |    14 |                                                 |
|    1 | SIMPLE      | em    | ALL  | NULL          | NULL      | NULL    | NULL                 | 36773 | Using where; Using join buffer (flat, BNL join) |
+------+-------------+-------+------+---------------+-----------+---------+----------------------+-------+-------------------------------------------------+

РЕДАКТИРОВАТЬ ВТОРОЕ

Я добавил внешний ключ на основе предложений с использованием следующего запроса:

ALTER TABLE `table_one`
ADD CONSTRAINT `model_id_fk_tbl_three`
FOREIGN KEY (`model_id`)
REFERENCES `table_three` (`fit_model_id`)

MYSQL все еще выполняет команду - там много строк, поэтому ожидал такого поведения. С помощью PHP я могу разбить запрос и построить свой массив таким образом, поэтому я предполагаю, что это, возможно, решает проблему - подумал, есть ли что-нибудь еще, что я могу сделать, чтобы попытаться сократить время выполнения?

5
treyBake 8 Окт 2018 в 11:19

2 ответа

Лучший ответ

Основываясь на комментариях всех и т. Д. Мне удалось выполнить несколько вещей, благодаря которым мой запрос выполнялся намного быстрее и не приводил к сбою моего скрипта.

1) Индексы

Я создал индекс своего table_three для поля fit_model_id:

CREATE INDEX fit_model ON `table_three` (`fit_model_id`);

Это заставило мой запрос LIMIT 1 перейти с 16 секунд до 0,03 секунды (в MYSQL CLI).

Однако 100 строк или около того все равно займет намного больше времени, чем я думал.

2) Внешние ключи

Я создал внешний ключ, который связал table_one. model_id = table_three. fit_model_id, используя следующий запрос:

ALTER TABLE `table_one`
ADD CONSTRAINT `model_id_fk_tbl_three`
FOREIGN KEY (`model_id`)
REFERENCES `table_three` (`fit_model_id`)

Это определенно помогло, но все же казалось, что можно сделать больше.

3) ОПТИМИЗАЦИЯ ТАБЛИЦЫ

Затем я использовал OPTIMIZE TABLE для этих таблиц:

  • table_one
  • table_three

Это заставило мой скрипт работать, а мой запрос работать как никогда быстро. Однако у меня возникла проблема с большим набором данных, поэтому я разрешил выполнение запроса в MYSQL CLI при увеличении LIMIT на 1000 для каждого времени выполнения сценария, чтобы помочь процессу индексирования, до 30 КБ строк, прежде чем он начал сбой.

CLI заняло 31 минуту и 8 секунд. Итак, я сделал это:

31 х 60 = 1860

1860 + 8 = 1868

1868/448476 = 0,0042

Таким образом, для завершения каждой строки потребовалось 0,0042 секунды, что на мой взгляд достаточно быстро.

Спасибо всем за комментарии и помощь в отладке и исправлении проблемы :)

3
treyBake 8 Окт 2018 в 10:42

На основании комментариев правильный ответ выглядит следующим образом:

  1. В случае длительного выполнения оператора select добавьте оператор EXPLAIN перед SELECT
  2. Проверить, являются ли possible_keys пустыми в подзапросах для определенных таблиц.
  3. Добавьте FOREIGN KEY для таблиц найдено на шаге 2. В случае большой таблицы рекомендуется настроить переменную MAX_EXECUTION_TIME (можно сделать для одного запроса)
  4. В случае массовых операций вставки / обновления / удаления OPTIMIZE TABLE также может регулировать производительность.
2
Anton 8 Окт 2018 в 10:40