Странное снижение производительности при использовании подзапроса - PullRequest
0 голосов
/ 28 октября 2018

У меня есть нано-сервер AWS с MySQL 5.5 для тестирования.Итак, имейте в виду, что сервер имеет ограниченные ресурсы (RAM, CPU, ...).

У меня есть таблица с именем "gpslocations".Первичный индекс имеет первичный ключ "GPSLocationID".В одном из его полей есть еще один вторичный индекс "userID".Таблица содержит 6583 записей .

Когда я запускаю этот запрос:

select * from gpslocations where GPSLocationID in (select max(GPSLocationID) from gpslocations where userID in (1,9) group by userID);

Я получаю две строки, и это занимает много времени:

+---------------+---------------------+------------+-----------+--------------------------------------+--------+--------------------------------------+-------+-----------+----------+---------------------+----------------+----------+-----------+-----------+
| GPSLocationID | lastUpdate          | latitude   | longitude | phoneNumber                          | userID | sessionID                            | speed | direction | distance | gpsTime             | locationMethod | accuracy | extraInfo | eventType |
+---------------+---------------------+------------+-----------+--------------------------------------+--------+--------------------------------------+-------+-----------+----------+---------------------+----------------+----------+-----------+-----------+
|          4107 | 2018-09-25 16:38:44 | 58.7641435 | 7.4868510 | e5d6fdff-9afe-44bb-a53a-3b454b12c9c6 |      9 | 77385f89-6b72-4b9e-b937-d2927959e0bd |     0 |         0 |      2.9 | 2018-09-25 18:38:43 | fused          |      455 | 0         | android   |
|          9822 | 2018-10-22 10:29:43 | 58.7794353 | 7.1952995 | 5240853e-2c36-4563-9dc3-238039de411e |      1 | 1fcad5af-c6ef-4bda-8fb2-d6e5688cf08a |     0 |         0 |    185.6 | 2018-10-22 12:29:41 | fused          |      129 | 0         | android   |
+---------------+---------------------+------------+-----------+--------------------------------------+--------+--------------------------------------+-------+-----------+----------+---------------------+----------------+----------+-----------+-----------+
2 rows in set (14.96 sec)

Когда я просто выполняю внутренний выбор:

select max(GPSLocationID) from gpslocations where userID in (1,9) group by userID;

Я получаю два значения очень быстро:

+--------------------+
| max(GPSLocationID) |
+--------------------+
|               9822 |
|               4107 |
+--------------------+
2 rows in set (0.00 sec)

Когда я беру эти два значения инапишите их вручную во внешнем select:

select * from gpslocations where GPSLocationID in (9822,4107);

Я получаю точно такой же результат, как и первый запрос, но в кратчайшие сроки!

+---------------+---------------------+------------+-----------+--------------------------------------+--------+--------------------------------------+-------+-----------+----------+---------------------+----------------+----------+-----------+-----------+
| GPSLocationID | lastUpdate          | latitude   | longitude | phoneNumber                          | userID | sessionID                            | speed | direction | distance | gpsTime             | locationMethod | accuracy | extraInfo | eventType |
+---------------+---------------------+------------+-----------+--------------------------------------+--------+--------------------------------------+-------+-----------+----------+---------------------+----------------+----------+-----------+-----------+
|          4107 | 2018-09-25 16:38:44 | 58.7641435 | 7.4868510 | e5d6fdff-9afe-44bb-a53a-3b454b12c9c6 |      9 | 77385f89-6b72-4b9e-b937-d2927959e0bd |     0 |         0 |      2.9 | 2018-09-25 18:38:43 | fused          |      455 | 0         | android   |
|          9822 | 2018-10-22 10:29:43 | 58.7794353 | 7.1952995 | 5240853e-2c36-4563-9dc3-238039de411e |      1 | 1fcad5af-c6ef-4bda-8fb2-d6e5688cf08a |     0 |         0 |    185.6 | 2018-10-22 12:29:41 | fused          |      129 | 0         | android   |
+---------------+---------------------+------------+-----------+--------------------------------------+--------+--------------------------------------+-------+-----------+----------+---------------------+----------------+----------+-----------+-----------+
2 rows in set (0.00 sec)

Может кто-нибудь объяснить такое огромное снижение производительности, когдадва простых и быстрых запроса объединены в один?

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

Вот вывод explain:

+----+--------------------+--------------+-------+----------------------+--------+---------+------+------+---------------------------------------+
| id | select_type        | table        | type  | possible_keys        | key    | key_len | ref  | rows | Extra                                 |
+----+--------------------+--------------+-------+----------------------+--------+---------+------+------+---------------------------------------+
|  1 | PRIMARY            | gpslocations | ALL   | NULL                 | NULL   | NULL    | NULL | 6648 | Using where                           |
|  2 | DEPENDENT SUBQUERY | gpslocations | range | userNameIndex,userID | userID | 5       | NULL |   11 | Using where; Using index for group-by |
+----+--------------------+--------------+-------+----------------------+--------+---------+------+------+---------------------------------------+
2 rows in set (0.00 sec)

1 Ответ

0 голосов
/ 28 октября 2018

in может иметь действительно плохие характеристики оптимизации. В вашей версии MySQL подзапрос, вероятно, выполняется один раз для каждой строки в gsplocations. Я думаю, что эта проблема с производительностью была исправлена ​​в более поздних версиях.

Я рекомендую вместо этого использовать коррелированный подзапрос:

select l.*
from gpslocations l
where l.GPSLocationID = (select max(l2.GPSLocationID)
                         from gpslocations l2
                         where l2.userID = l.userId
                        ) and
      l.userID in (1, 9);

И для этого вам нужен индекс на gpslocations(userID, GPSLocationID).

Другой альтернативой является join подход:

select l.*
from gpslocations l join
     (select l2.userID, max(l2.GPSLocationID)
      from gpslocations l2
      where l2.userID in (1, 9)
     ) l2
     on l2.userID = l.userId
where l.userID in (1, 9);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...