Эффективное хранение данных временных рядов: mySQL или плоские файлы? Многие таблицы (или файлы) или запросы с условием WHERE?

Каков наилучший способ хранения данных временных рядов тысяч (но может стать миллионами в скором времени) аппаратных датчиков реального мира? Сами датчики разные, некоторые просто фиксируют одну переменную, некоторые до десятка. Мне нужно хранить эти значения каждый час, и я не хочу удалять данные, которые старше х, т.е. Данные будут продолжать расти.

В настоящее время я использую базу данных mySQL для хранения этих временных рядов (которая также служит веб-интерфейсу, который показывает хорошие графики временных рядов для каждого датчика). У меня есть один стол для каждого датчика, который сейчас составляет около 11000 штук. Каждая таблица имеет макет, такой как "timestamp", "value1", [value2]... ".

Основная задача базы данных - больше выборок (каждый раз, когда кто-то смотрит на графики), чем вставки/обновления (один раз в час). Запрос выбора для отображения графика - это просто "SELECT * FROM $sensor_id ORDER BY timestamp", поэтому получение информации из моих операторов выбора довольно просто/эффективно.

Однако при наличии многих таблиц при резервном копировании базы данных возникают некоторые проблемы, так как я столкнулся с ограничениями LOCK (например, mysqldump: Got error: 23: Out of resources при открытии файла. /database/table _xyz.MYD ' Errcode: 24) при использовании LOCK TABLES "). Я могу обойти эту ошибку, но, очевидно, это заставило меня задуматься...

Итак, реальный вопрос, разбитый на следующие вопросы:

  • Насколько плохо мой подход иметь один стол для каждого датчика? Что, если вместо нескольких тысяч таблиц у меня было несколько миллионов (возможно, в ближайшем будущем мне придется иметь дело с такими многими датчиками)?
  • Сохраняет данные всех датчиков в одной комбинированной таблице с дополнительным столбцом, который поддерживает более высокий подход sensor_id, поскольку он, вероятно, замедлит мой оператор select большим количеством (SELECT * from all_sensors WHERE sensor_id= ' $sensor_id ')? Имейте в виду, что разные датчики измеряют разные вещи, поэтому в этой таблице будет несколько десятков столбцов вместо одного-нескольких, если у каждого датчика есть своя таблица?
  • Я также подумал о сохранении данных временного ряда NOT в mySQL, но вместо этого в файлах с плоским (CSV). Библиотека графиков, которую я использую для интерфейса (dygraphs), отлично разбирается в файлах CSV (плюс это даст мне возможность сделать их доступными для загрузки, что будет бонусом, но в настоящее время это не является требованием). Мне все еще нужна база данных для других связанных с интерфейсом вещей, но это означало бы наличие нескольких десятков таблиц вместо 11000 (или даже больше, если мы добавим больше датчиков).
  • Если я создам один файл для каждой таблицы, то я, вероятно, в конечном итоге столкнулся с ограничениями файловой системы (это раздел ext3, поэтому там ~ 32k файлов на лимит каталога). Таким образом, здесь также применяется тот же вопрос, что и выше: должен ли я сохранить его в одном большом файле, который содержит данные всех датчиков? Это, вероятно, замедлит мои чтения еще хуже, так как графическая библиотека должна будет читать гораздо более большой файл в памяти каждый раз, когда кто-то смотрит на график?

Что бы вы сделали?

Спасибо!

Ответ 1

Чтобы ответить на этот вопрос, мы должны сначала проанализировать проблему реального, с которой вы столкнулись.

Реальная проблема будет самой эффективной комбинацией написания и извлечения данных.

Давайте рассмотрим ваши выводы:

  • тысячи таблиц - ну, это нарушает назначение баз данных и затрудняет работу. Вы также ничего не получаете. По-прежнему существует поиск дисков, на этот раз с использованием многих дескрипторов файлов. Вы также должны знать имена таблиц, а там тысячи. Также сложно извлечь данные, для чего предназначены базы данных, - структурировать данные таким образом, чтобы вы могли легко перекрестно ссылаться на записи. Тысячи столов - не эффективны от перфорации. точка зрения. Неэффективна с точки зрения использования. Плохой выбор.

  • файл csv - он, вероятно, отлично подходит для сбора данных, если вам нужно полное содержимое сразу. Но это далеко не удалённо полезно для манипулирования или преобразования данных. Учитывая тот факт, что вы полагаетесь на конкретный макет, вы должны быть очень осторожны при записи в CSV. Если это вырастет до тысяч CSV файлов, вы не сделаете одолжение. Вы удалили все накладные расходы SQL (что не так уж и много), но вы ничего не сделали для извлечения частей набора данных. У вас также есть проблемы с получением исторических данных или перекрестной ссылкой на что-либо. Плохой выбор.

Идеальный сценарий будет иметь возможность доступа к любой части набора данных эффективным и быстрым способом без какого-либо изменения структуры.

И именно поэтому мы используем реляционные базы данных и почему мы выделяем целые серверы с большим количеством ОЗУ для этих баз данных.

В вашем случае вы используете таблицы MyISAM (расширение файла .MYD). Это старый формат хранения, который отлично подойдет для низкопроизводительного оборудования, которое использовалось в тот же день. Но в наши дни у нас отличные и быстрые компьютеры. Поэтому мы используем InnoDB и позволяем ему использовать много оперативной памяти, поэтому затраты на ввод-вывод сокращаются. Эта переменная, которая ее контролирует, называется innodb_buffer_pool_size - googling, которая даст значимые результаты.

Чтобы ответить на вопрос - эффективным, выполнимым решением будет использование одной таблицы, в которой вы храните информацию о датчике (идентификатор, название, описание) и другую таблицу, в которой хранятся показания датчика. Вы выделяете достаточное количество оперативной памяти или достаточно быстрое хранилище (SSD). Таблицы выглядят так:

CREATE TABLE sensors ( 
    id int unsigned not null auto_increment,
    sensor_title varchar(255) not null,
    description varchar(255) not null,
    date_created datetime,
    PRIMARY KEY(id)
) ENGINE = InnoDB DEFAULT CHARSET = UTF8;

CREATE TABLE sensor_readings (
    id int unsigned not null auto_increment,
    sensor_id int unsigned not null,
    date_created datetime,
    reading_value varchar(255), -- note: this column value might vary, I do not know what data type you need to hold value(s)
    PRIMARY KEY(id),
    FOREIGN KEY (sensor_id) REFERENCES sensors (id) ON DELETE CASCADE
) ENGINE = InnoDB DEFAULT CHARSET = UTF8;

InnoDB по умолчанию использует один плоский файл для всей базы данных/установки. Это устраняет проблему превышения предела файловой дескриптора ОС/файловой системы. Несколько или даже десятки миллионов записей не должны быть проблемой, если вы должны выделить 5-6 гигабайт ОЗУ для хранения рабочего набора данных в памяти - это позволит вам быстро получить доступ к данным.

Если бы я планировал такую ​​систему, это первый подход, который я сделал бы (лично). Оттуда это легко настраивается в зависимости от того, что вам нужно делать с этой информацией.