当等效的select查询没有时,使用临时表的MYSQL Update查询

时间:2016-03-21 23:29:25

标签: mysql sql-update innodb temp-tables explain

我有一个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',

1 个答案:

答案 0 :(得分:1)

猜测:

UPDATE正在更改索引值(readyState),对吗?这意味着有问题的索引正在改变UPDATE正在使用它?因此,UPDATE可能是"保护"它本身通过获取行(显然是以低效的方式),将它们扔到tmp表中,然后才执行操作。

"索引合并相交"几乎总是效率低于复合索引:INDEX(readyState, productName)(按任意顺序)。建议你添加。

由于您没有ORDER BY,其中" 30"将是不可预测的。建议你添加ORDER BY the-primary-key