MySQL Проблемы с производительностью при больших объемах данных

У меня есть программный проект, над которым я работаю на работе, который сводит меня с ума. Вот наша проблема: у нас есть ряд контактов с данными, которые необходимо регистрировать каждую секунду. Он должен включать время, азимут (массив из 360-1080 байт), диапазон и несколько других полей. Наша система также нуждается в возможности хранить эти данные до 30 дней. На практике может быть до 100 различных контактов, поэтому максимум может быть от 150 000 000 до 1 000 000 000 различных точек за 30 дней.

Я пытаюсь придумать лучший метод для хранения всех этих данных и последующего извлечения. Первой моей мыслью было использовать СУБД вроде MySQL. Поскольку я программист встраиваемых C / C ++, у меня очень мало опыта работы с MySQL с такими большими наборами данных.Я пробовал с ним работать с небольшими наборами данных, но не такими большими. Я создал приведенную ниже схему для двух таблиц, в которых будут храниться некоторые данные:

CREATE TABLE IF NOT EXISTS `HEADER_TABLE` (
  `header_id` tinyint(3) unsigned NOT NULL auto_increment,
  `sensor` varchar(10) NOT NULL,
  `bytes` smallint(5) unsigned NOT NULL,
  PRIMARY KEY  (`header_id`),
  UNIQUE KEY `header_id_UNIQUE` (`header_id`),
  UNIQUE KEY `sensor_UNIQUE` (`sensor`)
) ENGINE=MyISAM AUTO_INCREMENT=0 DEFAULT CHARSET=latin1;

CREATE TABLE IF NOT EXISTS `RAW_DATA_TABLE` (
  `internal_id` bigint(20) NOT NULL auto_increment,
  `time_sec` bigint(20) unsigned NOT NULL,
  `time_nsec` bigint(20) unsigned NOT NULL,
  `transverse` bit(1) NOT NULL default b'0',
  `data` varbinary(1080) NOT NULL,
  PRIMARY KEY  (`internal_id`,`time_sec`,`time_nsec`),
  UNIQUE KEY `internal_id_UNIQUE` (`internal_id`),
  KEY `time` (`time_sec`)
  KEY `internal_id` (`internal_id`)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;

CREATE TABLE IF NOT EXISTS `rel_RASTER_TABLE` (
  `internal_id` bigint(20) NOT NULL auto_increment,
  `raster_id` int(10) unsigned NOT NULL,
  `time_sec` bigint(20) unsigned NOT NULL,
  `time_nsec` bigint(20) unsigned NOT NULL,
  `header_id` tinyint(3) unsigned NOT NULL,
  `data_id` bigint(20) unsigned NOT NULL,
  PRIMARY KEY  (`internal_id`, `raster_id`,`time_sec`,`time_nsec`),
  KEY `raster_id` (`raster_id`),
  KEY `time` (`time_sec`),
  KEY `data` (`data_id`)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;

Таблица заголовка содержит только 10 строк и является статической. Он просто сообщает, с какого датчика были получены необработанные данные, и количество байтов, выводимых датчиком этого типа. RAW_DATA_TABLE по существу хранит необработанные данные пеленга (массив из 360-1080 байт, он представляет до трех выборок на градус). Rel_RASTER_TABLE содержит метаданные для RAW_DATA_TABLE, может быть несколько контактов, которые ссылаются на одну и ту же строку необработанных данных. data_id , найденный в rel_RASTER_TABLE, указывает на internal_id некоторой строки в RAW_DATA_TABLE, я сделал это, чтобы уменьшить количество необходимых записей.

Очевидно, как вы, наверное, догадались, у меня проблемы с производительностью при чтении и удалении из этой базы данных. Оператор нашего программного обеспечения может видеть данные в реальном времени по мере их поступления, а также переходить в режим реконструкции и накладывать диапазон данных за прошлый период, например, за прошедшую неделю. Наш внутренний сервер журналов захватывает строки истории и отправляет их на дисплей через интерфейс CORBA. Пока все это происходит, у меня есть рабочий поток, который удаляет 1000 строк за раз для данных, превышающих 30 дней. Это возможно в случае, если сеанс длится более 30 дней, что может случиться.

Система, которую мы в настоящее время внедрили, хорошо работает для небольших наборов данных, но не для больших наборов. Наши операторы select и delete могут занять до 2 минут для возврата результатов. Это полностью убивает производительность нашего потребительского потока в реальном времени.Я подозреваю, что мы неправильно проектируем наши схемы, выбираем неправильные ключи, неправильно оптимизируем наши SQL-запросы или какое-то их подмножество. Наши записи не будут затронуты, если другие операции не займут слишком много времени.

Вот пример SQL-запроса, который мы используем для получения данных истории:

SELECT 
  rel_RASTER_TABLE.time_sec, 
  rel_RASTER_TABLE.time_nsec, 
  RAW_DATA_TABLE.transverse, 
  HEADER_TABLE.bytes, 
  RAW_DATA_TABLE.data 
FROM 
  RASTER_DB.HEADER_TABLE, 
  RASTER_DB.RAW_DATA_TABLE, 
  RASTER_DB.rel_RASTER_TABLE 
WHERE 
  rel_RASTER_TABLE.raster_id = 2952704 AND 
  rel_RASTER_TABLE.time_sec >= 1315849228 AND 
  rel_RASTER_TABLE.time_sec <= 1315935628 AND 
  rel_RASTER_TABLE.data_id = RAW_DATA_TABLE.internal_id AND 
  rel_RASTER_TABLE.header_id = HEADER_TABLE.header_id;

Я заранее прошу прощения за такой длинный вопрос, но я использовал другие ресурсы, и это мое последнее средство. Думаю, я постараюсь быть как можно более информативным. Вы, ребята, видите, как я могу улучшить наш дизайн с первого взгляда? Или, в любом случае, мы можем оптимизировать наши операторы выбора и удаления для таких больших наборов данных? В настоящее время мы используем RHEL в качестве ОС и, к сожалению, не можем изменить конфигурацию оборудования на сервере (4 ГБ ОЗУ, четырехъядерный процессор). Мы используем C / C ++ и MySQL API. ЛЮБЫЕ улучшения скорости были бы ОЧЕНЬ полезными. Если вам нужно, чтобы я что-то прояснил, дайте мне знать. Спасибо!

РЕДАКТИРОВАТЬ: Кстати, если вы не можете предоставить конкретную помощь, может быть, вы можете связать меня с некоторыми отличными учебниками, с которыми вы столкнулись, по оптимизации запросов SQL, разработке схемы или настройке MySQL?

8
задан demarr 16 September 2011 в 18:22
поделиться