Во-первых, заранее извиняюсь за стену текста.Я прочитал все похожие вопросы / ответы, которые смог найти, но либо ответы не подходили для моего запроса, либо мне нужно было больше ясности, чтобы понять основную проблему и решение.
У меня есть таблицаразмеры файлов вместе с соответствующими датами и временными метками наблюдений.Все даты являются целыми числами времени эпохи UNIX в секундах:
mysql> describe name_servers;
+-----------------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------------+------------------+------+-----+---------+----------------+
| server_name | varchar(255) | YES | | NULL | |
| file_date | int(10) unsigned | YES | | NULL | |
| file_size | int(10) unsigned | YES | | NULL | |
| time | int(10) unsigned | YES | MUL | NULL | |
| poll_id | int(11) | NO | PRI | NULL | auto_increment |
+-----------------------+------------------+------+-----+---------+----------------+
5 rows in set (0.01 sec)
mysql> show index from name_servers;
+--------------+------------+--------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+--------------+------------+--------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| name_servers | 0 | PRIMARY | 1 | poll_id | A | 3523218 | NULL | NULL | | BTREE | | |
| name_servers | 0 | index_time_servername | 1 | time | A | 503316 | NULL | NULL | YES | BTREE | | |
| name_servers | 0 | index_time_servername | 2 | server_name | A | 3523218 | NULL | NULL | YES | BTREE | | |
+--------------+------------+--------------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
3 rows in set (0.00 sec)
Я должен отслеживать изменения размера файла, чтобы определить, уменьшается ли файл на> 20% в течение любого 48-часового периода.Обычно я пытался бы сделать это с функциями MySQL Window, но они не поддерживаются версией MySQL на моем сервере (5.6.37 - которую я не контролирую, так как сервер не управляется моей командой).В настоящее время я получаю текущий размер и максимальный размер (за последние 48 часов) с помощью внешнего запроса, который находит размер файла в текущей строке, и внутреннего подзапроса, который находит самый большой размер файла за предыдущие 48 часов (172 800 секунд).) количество строк:
mysql> select name_servers_outside.server_name,
-> name_servers_outside.file_size,
-> name_servers_outside.file_date,
-> name_servers_outside.time,
-> (select max(file_size) from name_servers where time > (name_servers_outside.time - 172800) and server_name = 'example_server') as max_file_size
-> from name_servers as name_servers_outside
-> where name_servers_outside.server_name = 'example_server'
-> and name_servers_outside.time > (UNIX_TIMESTAMP() - 172800)
-> limit 10;
+-------------------+-------------------+-------------------+------------+-----------------------+
| server_name | file_size | file_date | time | max_file_size |
+-------------------+-------------------+-------------------+------------+-----------------------+
| example_server | 1159544 | 1550382945 | 1550382985 | 1159580 |
| example_server | 1159544 | 1550382945 | 1550383195 | 1159580 |
| example_server | 1159544 | 1550382945 | 1550383255 | 1159580 |
| example_server | 1159544 | 1550382945 | 1550383316 | 1159580 |
| example_server | 1159544 | 1550382945 | 1550383376 | 1159580 |
| example_server | 1159544 | 1550382945 | 1550383435 | 1159580 |
| example_server | 1159544 | 1550382945 | 1550383496 | 1159580 |
| example_server | 1159544 | 1550382945 | 1550383555 | 1159580 |
| example_server | 1159544 | 1550382945 | 1550383616 | 1159580 |
| example_server | 1159544 | 1550382945 | 1550383676 | 1159580 |
+-------------------+-------------------+-------------------+------------+-----------------------+
10 rows in set (16.11 sec)
Простое извлечение этих 10 строк заняло 16 секунд, и в производственном процессе этот запрос должен будет получить более 150 строк.Внутренний запрос выполняет полное сканирование всех 3 миллионов + строк таблицы с сообщением «Диапазон проверен для каждой записи (карта индекса: 0x2)»:
mysql> explain
-> select name_servers_outside.server_name,
-> name_servers_outside.file_size,
-> name_servers_outside.file_date,
-> name_servers_outside.time,
-> (select max(file_size) from name_servers where time > (name_servers_outside.time - 172800) and server_name = 'example_server') as max_file_size
-> from name_servers as name_servers_outside
-> where name_servers_outside.server_name = 'example_server'
-> and name_servers_outside.time > (UNIX_TIMESTAMP() - 172800);
+----+--------------------+----------------------+-------+--------------------------+--------------------------+---------+------+---------+------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------------+----------------------+-------+--------------------------+--------------------------+---------+------+---------+------------------------------------------------+
| 1 | PRIMARY | name_servers_outside | range | index_time_servername | index_time_servername | 5 | NULL | 47302 | Using index condition; Using MRR |
| 2 | DEPENDENT SUBQUERY | name_servers | ALL | index_time_servername | NULL | NULL | NULL | 3533883 | Range checked for each record (index map: 0x2) |
+----+--------------------+----------------------+-------+--------------------------+--------------------------+---------+------+---------+------------------------------------------------+
2 rows in set (0.01 sec)
Проблемная частьКажется, что это:
time > (name_servers_outside.time - 172800)
Если я выполняю аналогичный запрос, используя статическое целочисленное значение вместо ссылки на столбец «name_servers_outside.time» в подзапросе, индексы используются, как ожидается, и запрос выполняется быстро:
time > (UNIX_TIMESTAMP() - 172800)
Модифицированный запрос:
mysql> select name_servers_outside.server_name,
-> name_servers_outside.file_size,
-> name_servers_outside.file_date,
-> name_servers_outside.time,
-> (select max(file_size) from name_servers where time > (UNIX_TIMESTAMP() - 172800) and server_name = 'example_server') as max_file_size
-> from name_servers as name_servers_outside
-> where name_servers_outside.server_name = 'example_server'
-> and name_servers_outside.time > (UNIX_TIMESTAMP() - 172800)
-> limit 10;
+--------------------+-------------------+-------------------+------------+-----------------------+
| server_name | file_size | file_date | time | max_file_size |
+--------------------+-------------------+-------------------+------------+-----------------------+
| example_server | 1159544 | 1550382945 | 1550382985 | 1159580 |
| example_server | 1159544 | 1550382945 | 1550383195 | 1159580 |
| example_server | 1159544 | 1550382945 | 1550383255 | 1159580 |
| example_server | 1159544 | 1550382945 | 1550383316 | 1159580 |
| example_server | 1159544 | 1550382945 | 1550383376 | 1159580 |
| example_server | 1159544 | 1550382945 | 1550383435 | 1159580 |
| example_server | 1159544 | 1550382945 | 1550383496 | 1159580 |
| example_server | 1159544 | 1550382945 | 1550383555 | 1159580 |
| example_server | 1159544 | 1550382945 | 1550383616 | 1159580 |
| example_server | 1159544 | 1550382945 | 1550383676 | 1159580 |
+--------------------+-------------------+-------------------+------------+-----------------------+
10 rows in set (0.01 sec)
mysql> explain
-> select name_servers_outside.server_name,
-> name_servers_outside.file_size,
-> name_servers_outside.file_date,
-> name_servers_outside.time,
-> (select max(file_size) from name_servers where time > (UNIX_TIMESTAMP() - 172800) and server_name = 'example_server') as max_file_size
-> from name_servers as name_servers_outside
-> where name_servers_outside.server_name = 'example_server'
-> and name_servers_outside.time > (UNIX_TIMESTAMP() - 172800)
-> limit 10;
+----+-------------+----------------------+-------+--------------------------+--------------------------+---------+------+-------+----------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+----------------------+-------+--------------------------+--------------------------+---------+------+-------+----------------------------------+
| 1 | PRIMARY | name_servers_outside | range | index_time_servername | index_time_servername | 5 | NULL | 49042 | Using index condition; Using MRR |
| 2 | SUBQUERY | name_servers | range | index_time_servername | index_time_servername | 5 | NULL | 49042 | Using index condition; Using MRR |
+----+-------------+----------------------+-------+--------------------------+--------------------------+---------+------+-------+----------------------------------+
2 rows in set (0.00 sec)
Спасибо, что прочитали со мной так далеко.Я снова прошу прощения за гигантскую стену текста, но я хотел убедиться, что я включил достаточно пояснительных деталей, чтобы четко определить проблему.
Теперь проблема, которую я пытаюсь решить, заключается в том, что мне нужно получитьнаибольшее значение file_size за 48 часов, предшествующих каждой строке.Поэтому каждая строка имеет свой уникальный временной диапазон для вычисления "max (file_size)".Затем он будет использоваться для расчета процентного изменения размера файла.Как упоминалось выше, я обычно хочу использовать оконные функции для этого, но они не поддерживаются моей версией MySQL (5.6.37), и я не могу обновиться до 8.0, так как я не являюсь владельцем этого сервера.
Как всегда, любые предложения приветствуются.Спасибо за чтение!