我在下面有一个加入4个表的查询。我添加了索引,并且使用索引的解释输出看起来很好(见下文)。
我可以进一步优化查询吗?
对于一些记录来说,modelXml相当大。对于一个大型项目,我得到22条记录,每条记录大约有2.5-3MB的modelXml数据,查询需要很长时间(总共返回69MB数据)。 我怀疑这是问题,但不知道如何处理它。 我正在阅读调整内部mysql变量,例如key_buffer_size和table_cache。这有什么帮助吗?
key_buffer_size当前设置为8384512(~8MB),table_cache设置为64 我该怎么把它增加到? 我应该考虑哪些其他变量来加速返回这些大数据?
欢迎任何其他建议。我是mysql的新手,但我真的想要变得更好。
SELECT `m`.`modelId`, `m`.`modelTypeId`, `m`.`modelXml`, `m`.`xmlSize`, `m`.`createdById`, `m`.`creationDate`, `m`.`modifiedDate`, `u`.`firstName`, `u`.`lastName` FROM `models_1` AS `m`
INNER JOIN `modelFolderAssociations_1` AS `mfa` ON m.modelId = mfa.modelIOId
INNER JOIN `modelFolders_1` AS `mf` ON mfa.folderId = mf.folderId
INNER JOIN `users_1` AS `u` ON m.createdById = u.userId
WHERE (m.projectId = 2) AND (mfa.folderId = 5) AND (mfa.modelIOType = 2) AND (m.modelTypeId = 2)
CREATE TABLE `models` (
`modelId` int(11) NOT NULL auto_increment,
`customerId` int(11) NOT NULL,
`groupId` int(11) NOT NULL,
`projectId` int(11) NOT NULL,
`createdById` int(11) NOT NULL,
`modelTypeId` int(11) NOT NULL,
`modelXml` longtext,
`modelSpecXml` longtext NOT NULL,
`xmlSize` bigint(20) NOT NULL default '0',
`creationDate` datetime NOT NULL,
`modifiedDate` datetime NOT NULL,
PRIMARY KEY (`modelId`,`customerId`)
) ENGINE=InnoDB AUTO_INCREMENT=75 DEFAULT CHARSET=utf8
CREATE TABLE `modelFolders` (
`folderId` int(11) NOT NULL auto_increment,
`customerId` int(11) NOT NULL,
`groupId` int(11) NOT NULL,
`projectId` int(11) NOT NULL,
`parentId` int(11) NOT NULL,
`folderName` varchar(64) NOT NULL,
`folderType` int(11) NOT NULL,
`editable` tinyint(1) NOT NULL default '1',
`nextDefaultNameNumber` int(11) NOT NULL default '1',
`creationDate` datetime NOT NULL,
`modifiedDate` datetime NOT NULL,
PRIMARY KEY (`folderId`,`customerId`),
KEY `parentId` (`parentId`)
) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8
CREATE TABLE `modelFolderAssociations` (
`associationId` int(11) NOT NULL auto_increment,
`customerId` int(11) NOT NULL,
`folderId` int(11) NOT NULL,
`projectId` int(11) NOT NULL,
`modelIOId` int(11) NOT NULL,
`modelIOType` tinyint(1) NOT NULL default '1',
`creationDate` datetime NOT NULL,
`modifiedDate` datetime NOT NULL,
PRIMARY KEY (`associationId`,`customerId`),
KEY `folderId` (`folderId`,`modelIOType`)
) ENGINE=InnoDB AUTO_INCREMENT=75 DEFAULT CHARSET=utf8
CREATE TABLE `users` (
`userId` int(11) NOT NULL auto_increment,
`customerId` int(11) NOT NULL,
`userName` varchar(50) NOT NULL,
`password` varchar(256) NOT NULL,
`firstName` varchar(50) default NULL,
`lastName` varchar(50) default NULL,
`creationDate` datetime NOT NULL,
`modifiedDate` datetime NOT NULL,
PRIMARY KEY (`userId`,`customerId`),
UNIQUE KEY `userName` (`userName`)
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8
解释输出
+----+-------------+-------------------------+--------+---------------+----------+---------+---------------------------------------------------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------------------------+--------+---------------+----------+---------+---------------------------------------------------+------+-------------+
| 1 | SIMPLE | modelFolders | const | PRIMARY | PRIMARY | 8 | const,const | 1 | Using index |
| 1 | SIMPLE | modelFolderAssociations | ref | folderId | folderId | 5 | const,const | 22 | Using where |
| 1 | SIMPLE | models | eq_ref | PRIMARY | PRIMARY | 8 | xa_system.modelFolderAssociations.modelIOId,const | 1 | Using where |
| 1 | SIMPLE | users | eq_ref | PRIMARY | PRIMARY | 8 | xa_system.models.createdById,const | 1 | |
+----+-------------+-------------------------+--------+---------------+----------+---------+---------------------------------------------------+------+-------------+
答案 0 :(得分:1)
拥有大型文本列,就像我用来存储XML所假设的那样,无论索引的结构如何,都会损害性能。
在这些情况下,最好将文本列移动到单独的表中,并按照您已经存储的字符串长度和CRC32进行索引。
CREATE TABLE MODEL_XML (
xmlId INT(11) unsigned NOT NULL auto_increment,
xmlSize BIGINT(20) NOT NULL default '0',
crc32 INT(11) unsigned NOT NULL,
xmlData LONGTEXT,
PRIMARY KEY (xmlId),
UNIQUE KEY (xmlSize, crc32)
)
然后,表格中具有重要索引的列的宽度将保持不变。
离。
modelXmlId INT(11) unsigned NOT NULL
specXmlId INT(11) unsigned NOT NULL
它还具有冗余文本(空字符串等)更节省空间的优点,因为它们共享一个xmlId,因此在DB中共享一行。
答案 1 :(得分:0)
您应该为外键编制索引,这对您的联接非常有帮助:
CREATE INDEX IDX_MODELS_CUSTID
on models (customerId)
CREATE INDEX IDX_FLDR_ASSOC_MODELIO
modelFolderAssociations(modelIOId)
CREATE INDEX IDX_FLDR_ASSOC_FLDRID
modelFolderAssociations(folderId)
等等。
答案 2 :(得分:0)
从SELECT子句中取下modelXml列后测试查询。
如果速度明显更好,那么缓慢来自要传输的数据量,而不是查询本身。
答案 3 :(得分:0)
您的索引并不总是与查询和联接匹配。如果WHERE和JOIN子句中的所有列都不在索引中,那么就强迫mysql查看基础行,这会导致性能下降,特别是因为模型行太宽了。
对于“modelFolderAssociations”,您为where子句创建了正确的复合键,但是您应该为要建模的连接包含modelIOId。
对于“模型”,您需要(modelId,projectId,modelTypeId,createdById)上的复合索引来覆盖来自mfa的传入链接,where子句中的两个项以及指向用户的出站链接。
对于“modelFolders”和“users”,您可以在主键中包含传入联接。
引擎只会使用一个索引,因此添加额外的索引单个索引(如Mike所建议的)将不会那么好。