MySQL性能问题涉及大量数据

dem*_*arr 8 c++ mysql performance

我有一个软件项目,我正在工作,这让我疯狂.这是我们的问题:我们有一系列数据联系人需要每秒记录一次.它需要包括时间,方位(360-1080字节的数组),范围和一些其他字段.我们的系统还需要能够存储这些数据长达30天.在实践中,最多可以有100个不同的联系人,因此最多可以在30天内从大约150,000,000点到大约1,000,000,000个不同的点.

我正在尝试考虑存储所有这些数据并在以后检索的最佳方法.我的第一个想法是使用一些像MySQL这样的RDBMS.作为一名嵌入式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;
Run Code Online (Sandbox Code Playgroud)

标头表只包含10行并且是静态的.它只是告诉原始数据来自哪个传感器,以及该类型传感器输出的字节数.RAW_DATA_TABLE实质上存储原始轴承数据(一个360-1080字节的数组,它表示每度最多三个样本).rel_RASTER_TABLE保存RAW_DATA_TABLE的元数据,可以有多个引用相同原始数据行的联系人.将data_id在rel_RASTER_TABLE指向发现internal_id在RAW_DATA_TABLE某一行的,我这样做是为了减少所需的写入量.

显然,正如您可能已经知道的那样,在从此数据库中读取和删除时,我遇到了性能问题.我们软件的操作员可以看到实时数据,并进入重建模式并覆盖过去一周的数据范围,例如过去一周.我们的后端日志记录服务器抓取历史记录行,并通过CORBA接口将它们发送到显示器.虽然这一切正在发生的事情,我有一个工作线程,在一个时间大于30天的数据删除1000行.如果会话运行超过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;
Run Code Online (Sandbox Code Playgroud)

我提前道歉这个是这样一个长的问题,但我已经挖掘出其他资源,这是我最后的手段.我想我会尽可能地描述你们有没有看到我乍看之下能改进我们的设计?或者,无论如何我们可以优化这些大型数据集的select和delete语句?我们目前正在运行RHEL作为操作系统,遗憾的是无法更改服务器上的硬件配置(4 GB RAM,四核).我们正在使用C/C++和MySQL API.任何速度改进都将非常有益.如果您需要我澄清任何事情,请告诉我.谢谢!

编辑:顺便说一句,如果你不能提供具体的帮助,也许你可以链接到我为优化SQL查询,架构设计或MySQL调优而遇到的一些优秀教程?

Kib*_*bee 4

您可以尝试的第一件事是对数据进行反规范化。在这种大小的数据集上,即使有索引,进行连接也需要非常密集的计算。将这三张表变成一张表。当然会有重复的数据,但如果没有连接,处理起来会容易得多。第二件事,看看你是否可以获得一台具有足够内存的机器来将整个表放入内存中。对于具有 24GB RAM 的机器来说,花费并不多(1000 美元或更少)。我不确定这是否能容纳您的整个数据集,但它也将极大地帮助您获得 SSD。对于未存储在内存中的任何内容,SSD 应该可以帮助您高速访问它。第三,研究其他数据存储技术,例如旨在处理非常大的数据集的BigTable 。