我有一个MYSQL表Foo,它在id上有主键,在不同列上有2个其他非主键。 Fiddle "select" example
我的实际表包含数百万行,因此解释的行为是不同的,即。它在2个非主索引上使用了Index_Merge。
当我运行以下Explain Update语句时:
explain UPDATE Foo
SET readyState = 1
WHERE readyState = 0
AND productName = 'OpenAM'
LIMIT 30;
Extra列包含"使用临时"。
当我运行等效的解释Select语句时:
Explain Select id, productName, readyState
FROM Foo
WHERE readyState = 0
AND productName = 'OpenAM'
Limit 30;
额外列不包含"使用临时"。
这对我的实际表格的影响是,当我更新时,有一个临时表创建了几百万行,因为它们都与限制30开始之前的更新条件相匹配。更新需要4 5秒,而select只需要约0.001s,因为它不会创建合并索引的临时表。我知道更新还需要更新所有3个索引(查询中使用的主要+ 2非主要)但如果花3秒钟更新3个索引中的30个索引行,我会感到震惊。
问题:有没有办法强制Update不使用不必要的临时表?我的印象是MYSQL以与select相同的方式处理Update查询计划。
如果更新而不是选择需要临时表,为什么?
编辑:
Show Create Table (removed a heap of columns since it is a very wide table):
CREATE TABLE Item (
ID int(11) NOT NULL AUTO_INCREMENT,
ImportId int(11) NOT NULL,
MerchantCategoryName varchar(200) NOT NULL,
HashId int(11) DEFAULT NULL,
Processing varchar(36) DEFAULT NULL,
Status int(11) NOT NULL,
AuditWho varchar(200) NOT NULL,
AuditWhen datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (ID),
KEY idx_Processing_Item (Processing),
KEY idx_Status_Item (Status),
KEY idx_MerchantCategoryName_Item (MerchantCategoryName),
KEY fk_Import_Item (ImportId),
KEY fk_Hash_Item (HashId),
CONSTRAINT fk_Hash_Item FOREIGN KEY (HashId) REFERENCES Hash (ID),
CONSTRAINT fk_Import_Item FOREIGN KEY (ImportId) REFERENCES Import (ID)
) ENGINE=InnoDB AUTO_INCREMENT=12004589 DEFAULT CHARSET=utf8
更新声明
explain UPDATE Item
SET Processing = 'd53dbc91-eef4-11e5-a3a6-06f88beef4f3',
Status = 2,
AuditWho = 'name',
AuditWhen = now()
WHERE EventId = 1
AND Processing is null
AND Status = 1
LIMIT 30;
结果:
'id','select_type','table','type','possible_keys','key','key_len','ref','rows','Extra',
'1','SIMPLE','Item','index_merge','idx_Processing_Item,idx_Status_Item,fk_Import_Item','idx_Processing_Item,idx_Status_Item,fk_Import_Item','111,4,4',\N,'1362610','Using intersect(idx_Processing_Item,idx_Status_Item,fk_Import_Item); Using where; Using temporary',
选择查询
explain select ID from Item where Status = 1 and Processing is null and ImportId = 1 limit 30;
结果:
'id','select_type','table','type','possible_keys','key','key_len','ref','rows','Extra',
'1','SIMPLE','Item','index_merge','idx_Processing_Item,idx_Status_Item,fk_ImportEvent_Item','idx_Processing_Item,idx_Status_Item,fk_Import_Item','111,4,4',\N,'1362610','Using intersect(idx_Processing_ItemPending,idx_Status_ItemPending,fk_ImportEvent_ItemPending); Using where; Using index',
答案 0 :(得分:1)
UPDATE
正在更改索引值(readyState
),对吗?这意味着有问题的索引正在改变UPDATE
正在使用它?因此,UPDATE
可能是"保护"它本身通过获取行(显然是以低效的方式),将它们扔到tmp表中,然后才执行操作。
"索引合并相交"几乎总是效率低于复合索引:INDEX(readyState, productName)
(按任意顺序)。建议你添加。
由于您没有ORDER BY
,其中" 30"将是不可预测的。建议你添加ORDER BY the-primary-key
。