进一步优化此查询? - 索引但仍然缓慢

时间:2011-03-31 23:01:48

标签: php mysql database

我在下面有一个加入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 |             |
+----+-------------+-------------------------+--------+---------------+----------+---------+---------------------------------------------------+------+-------------+

4 个答案:

答案 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所建议的)将不会那么好。