Правильно ли оптимизировать числовые данные MySQL для запросов диапазона дат? - PullRequest
0 голосов
/ 03 мая 2018

Итак, у меня есть таблица с большим количеством числовых данных: http://sqlfiddle.com/#!9/dfdb35/4/0

В настоящее время имеется 60 миллионов строк.

Мне нужно запросить эти данные, чтобы получить ближайшую строку для определенных date_added и name, в приведенном выше примере есть запрос, который я использую для этого (где я использую >= 'targetdate' и LIMIT 1, чтобы получить ближайший ).

Моя проблема в том, что эти данные не упорядочены по дате, поэтому при возврате результатов мне нужно указать ORDER BY date_added (или он не возвращает правильную строку). В настоящее время выполнение этого для строк 60M занимает хорошие 90 секунд из-за этого условия ORDER BY.

Есть ли способы, которыми я могу дополнительно оптимизировать это? Я уже проиндексировал столбцы date_added и name, поэтому я не совсем уверен, что еще можно сделать. Я подумал о создании новой таблицы с переупорядочением данных в порядке date_added, но это нецелесообразно, поскольку новые записи для старых данных необходимо регулярно добавлять.

Я сохранил числовые данные как десятичные, поскольку они могут быть очень маленькими (например, 0.0000243), но они также могут быть очень большими (например, 12345678) или даже и то и другое (например, 12345678.0000243). Возможно, хранение этих данных другим способом будет более эффективным? Есть идеи? Я приказал книге High Performance MySQL продолжить самостоятельное изучение этого вопроса, но это не будет раздражающим какое-то время, и эта таблица растет довольно быстро, поэтому проблема усугубляется (увеличивается примерно на 300 тысяч строк в день).

Выход EXPLAIN:

id: 1
select_type: SIMPLE
table: numeric_data
partitions: NULL
type: range
possible_keys: date_added,name
key: date_added
key_len: 5
ref: NULL
rows: 29222232
filtered: 0.16
Extra: Using index condition; Using where

Ответы [ 2 ]

0 голосов
/ 03 мая 2018

Добавить составной индекс по имени и дате. Приведенный выше запрос будет выполняться без использования файловой сортировки.

Альтернативный способ запроса:

SELECT date_added, data_1, data_2, data_3, data_4, data_5, data_6, data_7, data_8, data_9
FROM numeric_data
WHERE date_added = 
(select min(date_added) from numeric_data where date_added >= '2018-05-03 11:00:00' and name = 'aaa')
and name = 'aaa'
limit 1;  

Скрипка: http://sqlfiddle.com/#!9/4e8d89/1.

0 голосов
/ 03 мая 2018

Вы можете использовать разбиение диапазона:

https://dev.mysql.com/doc/refman/5.7/en/partitioning-range.html

Вам необходимо определить свои разделы в зависимости от диапазона дат, который у вас есть.

 CREATE TABLE `numeric_data` (
 `id` int(255) NOT NULL AUTO_INCREMENT,
 `date_added` datetime NOT NULL,
 `name` varchar(8) COLLATE utf8mb4_unicode_ci NOT NULL,
 `data_1` decimal(30,17) NOT NULL,
 `data_2` decimal(30,17) NOT NULL,
 `data_3` decimal(30,17) NOT NULL,
 `data_4` decimal(30,17) NOT NULL,
 `data_5` decimal(30,17) NOT NULL,
 `data_6` decimal(30,17) NOT NULL,
 `data_7` decimal(30,17) NOT NULL,
 `data_8` decimal(30,17) NOT NULL,
 `data_9` decimal(30,17) NOT NULL,
 PRIMARY KEY (`id`),
 KEY `date_added` (`date_added`),
 KEY `name` (`name`)
) ENGINE=InnoDB AUTO_INCREMENT=60000000 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
      PARTITION BY RANGE( TO_DAYS(date_added) ) (
        PARTITION p1 VALUES LESS THAN (TO_DAYS('2018-01-01')),
        PARTITION p2 VALUES LESS THAN (TO_DAYS('2018-02-01')),
        PARTITION p3 VALUES LESS THAN (TO_DAYS('2018-03-01')),
        PARTITION p4 VALUES LESS THAN (TO_DAYS('2018-04-01')),
        PARTITION future VALUES LESS THAN MAXVALUE
      );

Для приведенного ниже запроса будет использоваться только раздел «будущее»:

SELECT date_added, data_1, data_2, data_3, data_4, data_5, data_6, data_7, data_8, data_9
FROM numeric_data
WHERE date_added >= '2018-05-03 11:00:00'
AND name = 'aaa'
ORDER BY date_added LIMIT 1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...