web-dev-qa-db-ja.com

UPDATEはINDEXを使用しませんが、SELECTは使用します

私は実際にここで問題を理解するのに苦労しています。私は、UPDATEがWHERE句のインデックスから利益を得ると言ってどこでも読みました。

ただし、このクエリは、

UPDATE `documents` SET `read`="1" WHERE `docid` IN (<subquery>)

しないインデックスを使用しているようです。テーブルdocumentsには、docidreadのインデックスがあります。

EXPLAINを実行すると、possible_keys = NULLおよびrows = 8011008(テーブル全体)が表示されます。サブクエリはキーを使用し、適切な行(2行)を読み取ります。

一方、このクエリは:

SELECT * FROM `documents` WHERE `docid` IN (<subquery>)

使用しますdocidのインデックスで、非常に高速に実行されます。 (EXPLAINのように)必要以上の行を読み取りますが、完全に許容されます。

これについて何か説明はありますか?
私はMariaDB 10を使用しています。

おもしろいメモとして(SELECTに関して)、<subquery>UNIONを使用している場合、サブクエリは適切な数の行を取得しているように見えますが、プライマリクエリはインデックスを使用せず、テーブル全体をスキャンします。

UPDATEJOINの代わりにINを使用すると、インデックスが適切に使用されます。 JOINを使用して問題を解決しました。

2
Nuno

「UPDATEはINDEXを使用しませんが、SELECTは使用します」という質問に対処するには...

ごく最近まで、UPDATEsの多くはSELECTsとは異なるコードで処理されていました。最近、Oracleブランチに統合がありました。 MariaDBにはまだ導入されていないと思います。

また、構造体IN ( SELECT ... )は、5.6まで最適化されていません。この場合も、MariaDBには、この領域の5.6/5.7の改善の一部がまだ含まれている場合と含まれていない場合があります。

ほとんどの場合、... IN ( SELECT ... )JOIN ... ON ...に変換することをお勧めします。これはUPDATEで可能です。 「マルチテーブルUPDATE」を参照してください。

特定のケースの詳細については、SHOW CREATE TABLEおよびEXPLAIN SELECT ...を提供してください。

Oracleブランチが必然的に物事をより良いものにするということではありません。むしろ違いがあるかもしれないということです。

4
Rick James