在my previous question上发表评论之后,我在这里描述了导致我使用枚举列的数据库架构导致性能不佳的问题。
(请参阅此问题底部的编辑以获得我的总体结论)
我使用基因表达数据。我们捕获condition
s表达任何gene
(例如,说基因X在[器官Y-生命阶段Z]的条件下表达)。我有4个dataType
可以生成这样的表达数据。因此,我的原始数据存储在不同的表中(这只是一个说明性示例,原始数据要复杂得多):
+--------------------+------------------------------------+------+-----+--------------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------------------+------------------------------------+------+-----+--------------+-------+
| geneId | int(10) unsigned | NO | PRI | NULL | |
| evidenceId | varchar(70) | NO | PRI | NULL | |
| experimentId | varchar(70) | NO | MUL | NULL | |
| conditionId | mediumint(8) unsigned | NO | MUL | NULL | |
| expressionId | int(10) unsigned | NO | MUL | NULL | |
| detectionFlag | enum('expressed', 'not expressed') | NO | | NULL | |
| quality | enum('low quality','high quality') | NO | | NULL | |
+--------------------+------------------------------------+------+-----+--------------+-------+
每个dataType
我有一个这样的表。现在,典型的查询将同时请求数千个基因。因为数据非常大(每个表中有数亿行),并且包含冗余值(相同gene
的大量证据,相同证据的gene
吨,所以单独查询每个表是非常慢的。出于这个原因,我们有一个预先计算的“汇总”表,根据这4个表中的信息计算:
+----------------+-----------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------+-----------------------+------+-----+---------+----------------+
| expressionId | int(10) unsigned | NO | PRI | NULL | auto_increment |
| geneId | int(10) unsigned | NO | MUL | NULL | |
| conditionId | mediumint(8) unsigned | NO | MUL | NULL | |
+----------------+-----------------------+------+-----+---------+----------------+
(请注意,此表中还有其他有用的列)。 expressionId
字段允许返回原始数据。
现在我的问题是:
summaryQuality
本身支持表达式行的不同实验的数量计算condition
,同时还考虑任何相关的condition
(我告诉了什么是相关的condition
,但是,是的,condition
之间的关系可以存储在另一个表中。summaryQuality
s的任意组合的表达式行的实验求和来计算“全局”dataType
。例如,他们应该能够说“从dataType1和dataType2中的实验总和中给出x实验支持的结果”,或者“从dataType1和dataType2以及dataType3和dataType4中的实验总和中给出y实验支持的结果” 所以我最终得到了以下设计:
+--------------------------+-----------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------------------+-----------------------+------+-----+---------+----------------+
| expressionId | int(10) unsigned | NO | PRI | NULL | auto_increment |
| geneId | int(10) unsigned | NO | MUL | NULL | |
| conditionId | mediumint(8) unsigned | NO | MUL | NULL | |
| dataType1ExperimentCount | smallint(5) unsigned | NO | | 0 | |
| dataType2ExperimentCount | smallint(5) unsigned | NO | | 0 | |
| dataType3ExperimentCount | smallint(5) unsigned | NO | | 0 | |
| dataType4ExperimentCount | smallint(5) unsigned | NO | | 0 | |
+--------------------------+-----------------------+------+-----+---------+----------------+
此表中的行是通过考虑给定dataType
的所有condition
和所有相关conditionId
来预先计算的。计算起来非常慢。因此,该表有数亿行。
现在我的查询如下:
SELECT * FROM myTable WHERE geneId IN (?, ?, ?, ...) AND (dataType1ExperimentCount + dataType2ExperimentCount + dataType3ExperimentCount + dataType4ExperimentCount) >= ?;
SELECT * FROM myTable WHERE geneId IN (?, ?, ?, ...) AND (dataType1ExperimentCount + dataType2ExperimentCount) >= ?;
表现非常糟糕,因为根据我之前的问题中的答案,此类查询无法使用索引。我需要允许dataType
s的任意组合。我需要在将来允许添加新的dataType
(从而使组合的数量达到32或64非常快)。
我能想出什么更好的设计?
编辑以下用户Rick James的请求,show create table:
CREATE TABLE `expression` (
`expressionId` int(10) unsigned NOT NULL AUTO_INCREMENT,
`geneId` mediumint(8) unsigned NOT NULL,
`conditionId` mediumint(8) unsigned NOT NULL,
`dataType1ExperimentCount` smallint(5) unsigned NOT NULL DEFAULT '0',
`dataType2ExperimentCount` smallint(5) unsigned NOT NULL DEFAULT '0',
`dataType3ExperimentCount` smallint(5) unsigned NOT NULL DEFAULT '0',
`dataType4ExperimentCount` smallint(5) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`expressionId`),
UNIQUE KEY `geneId` (`geneId`,`conditionId`),
KEY `conditionId` (`conditionId`),
CONSTRAINT `expression_ibfk_1` FOREIGN KEY (`geneId`) REFERENCES `gene` (`geneId`) ON DELETE CASCADE,
CONSTRAINT `expression_ibfk_2` FOREIGN KEY (`conditionId`) REFERENCES `cond` (`conditionId`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
(并且,是的,给定的geneId
表中的行数少于给定的conditionId
,因此多个唯一键的排序正确。)
编辑,总体结论:
答案 0 :(得分:1)
从上一篇文章:
也许尝试MySQL的列存储引擎?像ICE或InfiniDB。您不需要索引,因为它们存储的数据类似于基于行的存储索引。对于某些用例,这种类型的存储更快,而对其他用例则更慢。数据仓库,聚合,分析查询等应该会受益。
有社区版本以及付费企业版。
答案 1 :(得分:1)
而不是
PRIMARY KEY (`expressionId`),
UNIQUE KEY `geneId` (`geneId`,`conditionId`),
使用
PRIMARY KEY(`geneId`,`conditionId`),
INDEX (`expressionId`),
如果没有其他表正在重新引用expressionId
,请删除该列及其上的索引。
为什么这有帮助?数据使用主键进行聚类;你正在通过geneId
查找数据,这是PK的开始;因此,可以更有效地获取数据,特别是如果表格比innodb_buffer_pool_size
大得多(应该是RAM的70%左右)。