Несколько таблиц или использовать разбиение? - PullRequest
3 голосов
/ 05 сентября 2011

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

Я ищу для хранения данных временных рядов в MySQL для большого количества датчиков (500 и растет), каждый из которых обеспечивает одно значение с плавающей точкой с 5-минутными интервалами.В простейшем случае структура будет выглядеть так: - gauge_id - timestamp - значение

(где gauge_id и timestamp объединяются в качестве первичного ключа)

Это означает примерно 105120 строк на датчик в год - все, что необходимохраниться в течение 10 или 20 лет.Тогда для 1000 датчиков мы будем рассматривать 100 миллионов записей в год.

Данные записываются в пакетах, обычно значения для каждого канала объединяются в файл XML из удаленного источника и считываются в базу данных каждый час.или ежедневно.Таким образом, самое большее, количество вставок в час равно количеству датчиков.

Операции чтения данных будут выполняться для каждого датчика (поэтому операции объединения данных между датчиками не будут) в зависимости от временного диапазона.Так, например, чтобы получить все значения для датчика X между двумя датами.Обычно это также включает в себя некоторую форму функции агрегации / интерполяции - поэтому пользователь может захотеть увидеть среднесуточные значения или максимальные значения за неделю и т. Д. Для произвольных диапазонов.Опять же, сравнительно небольшое количество операций чтения, но для этого требуется ответ менее чем за 1 секунду от MySQL.

На этом этапе я склоняюсь к 1 таблице на один датчик, а не делаю одну огромную таблицу в MySQL на gauge_id.Логика заключается в том, что это облегчит разбиение в дальнейшем, упростит резервное копирование и, по существу, облегчит удаление / восстановление датчиков, если на любом этапе возникнут ошибки в данных.Затраты на операции записи и чтения немного сложнее.

Есть мысли по этому поводу?

-------- ОБНОВЛЕНИЕ --------

Я провел несколько тестов на своем MacBook 2,4 ГГц Core 2 Duo, 4 ГБ ОЗУ.

Настройте следующую таблицу:

CREATE TABLE `test` (
  `channel_id` int(10) NOT NULL,
  `time` datetime NOT NULL,
  `value` int(10) NOT NULL,
  KEY `channel_id` (`channel_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

Заполнено с помощью хранимой процедуры:

CREATE PROCEDURE `addTestData`(IN ID INT, IN RECORDS INT)
    BEGIN
        DECLARE i INT DEFAULT 1;
        DECLARE j DATETIME DEFAULT '1970-01-01 00:00:00';
           WHILE (i<=RECORDS) DO
              INSERT INTO test VALUES(ID,j,999);
              SET i=i+1;
              SET j= j + INTERVAL 15 MINUTE;
           END WHILE;
    END $$

пока я звонил, чтобы создать первые 1 миллион записей

call addTestData(1,1000000);

вставка, выполненная за 47 секунд

SELECT * FROM `test` WHERE channel_id = 1 and YEAR(time) = '1970';

, выполненная за 0,0006 секунд

SELECT AVG(value) as value, DATE(time) as date FROM `test` 
WHERE channel_id = 1 and YEAR(time) = '1970' group by date;

выполняется за 4,6 с (функции MAX, SUM выполняются одновременно).

после добавления еще 4-х датчиков:

call addTestData(2,1000000);
call addTestData(3,1000000);
call addTestData(4,1000000);
call addTestData(5,1000000);

вставка выполняется за 47 с, 78мегабайты, использованные для таблицы

Я выполнил те же два запроса - и получил точно такое же время выполнения, что и 1 миллион записей в таблице (4,6 секунды для более крупного запроса).

Итак,исключить потенциальное использование для шардинга, резервного копирования и будущих изменений на аппаратном уровне в таблице любого отдельного датчика (т. е. несколько показаний, изменениеинтервал данных), как представляется, нет необходимости разбивать на несколько таблиц для обозримого.Даже не пытался запустить запрос с разделами, похоже, не было никаких причин.

-------- ОДНАКО -------------

Поскольку 4,6 секунды для запроса не являются идеальными, нам, очевидно, необходимо провести некоторую оптимизацию.В качестве первого шага я реструктурировал запрос:

SELECT 
    AVG(value) as value, 
    DATE(time) as date 
FROM 
    (SELECT * FROM test 
    WHERE channel_id = 1 and YEAR(time) = '1970') 
    as temp 
group by date;

Выполнение таблицы с 5 миллионами записей (более 5 идентификаторов канала): запрос занимает 4,3 секунды.Если я запускаю его на столе с 1 каналом, 1 миллионом записей, он запускается за 0,36 секунды !!Немного почесывая голову над этим ...

Секционирование таблицы из 5 миллионов записей

ALTER TABLE test PARTITION BY HASH(channel_id) PARTITIONS 5;

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

1 Ответ

3 голосов
/ 05 сентября 2011

Для меня в вашем сценарии нет ничего, что оправдывало бы разбиение по датчику, если бы у вас был индекс по gauge_id, производительность не была бы проблемой, потому что MySql найдет строки, связанные с определенным датчиком, немедленно, используя индекс, после этого другогооперации будут аналогичны работе с отдельной таблицей для каждого датчика.

Единственная ситуация, в которой разделение может быть оправданным, - это если вы получаете доступ к самым последним данным датчика (скажем, самым новым 10%) очень часто, чем к старым данным (оставшиеся 90%), если в этом случае разбиение на две «недавние» и «архивные» таблицы может дать вам большое преимущество в производительности.

Если ваша операция с отдельными таблицами не включает индекс, то та же операцияне должно занимать намного больше времени в объединенной таблице, потому что MySql сначала сужает результаты до определенных строк датчика, используя индекс для gauge_id, если операция включает в себя индекс, вы должны сделать индекс многостолбцовым в объединенной таблице, начиная с«gauge_iНапример, INDEX( timestamp ) для отдельных таблиц должно стать INDEX( gauge_id, timestamp ), тогда в большинстве случаев операция займет то же время, что и для отдельных таблиц.Также не стоит откладывать на цифры, вроде «500 миллионов строк», базы данных предназначены для работы с таким количеством данных.

Мои замечания в основном основаны на опыте почти каждый раз, когда я был в вашей ситуации и решилчтобы перейти к отдельным таблицам, по тем или иным причинам я закончил объединением таблиц в одну, и в большинстве случаев, когда проект созревает, это болезненный процесс.Я действительно испытал «реляционные базы данных не предназначены для такого использования».

Мне очень нравится слышать мнение других об этом, кстати, перед тем, как пойти в любую сторону, нужно много тестировать, у MySql много неожиданное поведение .

...