私はIDにプライマリキーを持つMYSQLテーブルFooと、異なるカラムに2つの他の非プライマリキーを持っています。 Fiddle "select" exampleMYSQL同等の選択クエリがない場合にテンポラリテーブルを使用してクエリを更新
実際の表には何百万行も含まれているため、説明の動作が異なります。 2つの非プライマリインデックスでIndex_Mergeを使用します。
私は、以下の説明UPDATEステートメントを実行
:explain UPDATE Foo
SET readyState = 1
WHERE readyState = 0
AND productName = 'OpenAM'
LIMIT 30;
余分な列が含まれているが、 "一時的な使用" を参照してください。
Explain Select id, productName, readyState
FROM Foo
WHERE readyState = 0
AND productName = 'OpenAM'
Limit 30;
エクストラ列はは "一時の使用" を含んでいない:
私は同等のものを実行するSELECT文を説明します。
これは私の実際のテーブルに与える影響は、私が更新すると、限界30キックが入る前に更新の条件に一致する数百万行の一時テーブルが作成されていることです。 -5秒ですが、selectはマージされたインデックスの一時テーブルを作成しないため、0.001秒しかかかりません。私は更新プログラムが3つのインデックス(プライマリ+ 2プライマリはクエリで使用されている)をすべて更新する必要があることを理解していますが、3つのインデックスで30のインデックス行を更新するのに4秒かかる場合は驚いています。
質問:強制的に更新プログラムが不要な一時テーブルを使用しないようにする方法はありますか?私は、MYSQLがSELECTクエリと同じようにUpdateクエリプランを扱ったという印象を受けました。
なぜなら、選択肢ではなく一時表が更新に必要なのはなぜですか?
EDIT:
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
UPDATE文
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',
'SHOW CREATE TABLE'と' EXPLAIN'を提供してください。 –
'LIMIT'を' ORDER BY'なしで使うと、予期しない結果が出ることがあります。 –
この特定のクエリでは、どの行が更新または選択されているか気にしません。私はIDで注文を説明しただけで、一時的な使用を削除しましたが、それをfilesortを使用するように変更し、今更新を実行するのにずっと時間がかかります。 –