在对上一个问题进行评论之后,我在这里描述了导致我拥有带有枚举列的数据库架构的问题,从而导致性能下降。
(有关我的总体结论,请参见此问题底部的编辑)
我处理基因表达数据。我们捕获了condition任何s在其中gene表达(例如,说基因X在条件[器官Y-生命阶段Z]中表达)。我有4 dataTypes可以产生这样的表达数据。因此,我的原始数据存储在不同的表中,例如(这只是一个示例,原始数据要复杂得多):
condition
gene
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字段允许返回原始数据。
expressionId
现在我的问题是:
summaryQuality
因此,我完成了以下设计:
+--------------------------+-----------------------+------+-----+---------+----------------+ | 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。这是非常缓慢的计算。该表因此具有数亿行。
conditionId
现在我的查询看起来像:
SELECT * FROM myTable WHERE geneId IN (?, ?, ?, ...) AND (dataType1ExperimentCount + dataType2ExperimentCount + dataType3ExperimentCount + dataType4ExperimentCount) >= ?; SELECT * FROM myTable WHERE geneId IN (?, ?, ?, ...) AND (dataType1ExperimentCount + dataType2ExperimentCount) >= ?;
根据我上一个问题的答案,性能非常差,因为此类查询无法使用索引。我需要允许dataTypes的任意组合。我需要dataType在将来允许添加new (从而使组合数达到32或64的速度非常快)。
我能提出什么更好的设计?
编辑用户Rick James的以下请求,显示创建表:
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,因此正确地对多个唯一键进行排序)。
geneId
编辑,总体结论 :
代替
PRIMARY KEY (`expressionId`), UNIQUE KEY `geneId` (`geneId`,`conditionId`),
使用
PRIMARY KEY(`geneId`,`conditionId`), INDEX (`expressionId`),
如果没有其他表在引用expressionId,请摆脱该列及其上的索引。
为什么有帮助?数据通过主键聚类;您正在按来查找数据geneId,这是PK的开始;因此,可以更有效地获取数据,尤其是如果该表要大得多innodb_buffer_pool_size(应该是RAM的70%左右)时。
innodb_buffer_pool_size